Files
JP_KDDI_LFPS_48100/LFP_Manager/Function/csSerialCommFunction.cs
2025-12-19 13:59:34 +09:00

970 lines
46 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LFP_Manager.DataStructure;
using LFP_Manager.Utils;
using LFP_Manager.Controls;
using System.Web.Services.Description;
using System.Data.Entity.Core.Common.CommandTrees;
using DevExpress.XtraRichEdit.Fields.Expression;
using DevExpress.XtraRichEdit.Layout;
using DevExpress.XtraPrinting.Native.LayoutAdjustment;
namespace LFP_Manager.Function
{
class csSerialCommFunction
{
static readonly byte[] auchCRCHi = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40
};
static readonly byte[] auchCRCLo = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,0x40
};
public const byte READ_COIL_STATUS = 0x01;
public const byte READ_HOLDING_REG = 0x03;
public const byte READ_INPUT_REG = 0x04; //Byul 구문 추가 필요
public const byte FORCE_SINGLE_COIL = 0x05;
public const byte PRESET_SINGLE_REG = 0x06;
public const byte PRESET_MULTI_REG = 0x10;
public const byte WRITE_COIL_REG = 0x0F;
public const byte ERROR_REG = 0x90;
public const byte FW_FLASH_ERASE_CMD = 0x43;
public const byte FW_FLASH_WRITE_CMD = 0x31;
public const byte NO_CMD = 0xFF;
public static byte[] GetCRC(byte[] pby, int nSize)
{
ushort uIndex, i;
ushort crc;
byte uchCRCHi = 0xff;
byte uchCRCLo = 0xff;
byte[] result = new byte[2];
for (i = 0; i < nSize; i++)
{
uIndex = (ushort)((int)uchCRCLo ^ (int)pby[i]);
uchCRCLo = (byte)(uchCRCHi ^ auchCRCHi[uIndex]);
uchCRCHi = auchCRCLo[uIndex];
}
crc = (ushort)((uchCRCHi << 8) | uchCRCLo);
result[0] = (byte)(crc >> 8);
result[1] = (byte)(crc >> 0);
return result;
}
static public byte[] MakeReadRegisterData(ushort DevID, ushort cmd, ushort ReadAddr, ushort Size)
{
byte[] result = new byte[8];
byte[] crc;
result[0] = (byte)DevID; // Device ID
result[1] = (byte)cmd; // Command
result[2] = (byte)(ReadAddr >> 8); // Register Address MSB
result[3] = (byte)(ReadAddr >> 0); // Register Address LSB
result[4] = (byte)(Size >> 8); // Count of Register MSB
result[5] = (byte)(Size >> 0); // Count of Register LSB
crc = GetCRC(result, 6);
result[6] = crc[1]; // CRCH
result[7] = crc[0]; // CRCL
return result;
}
static public byte[] MakeWriteCoilData(ushort DevID, ushort WriteAddr, short WriteData)
{
byte[] result = new byte[7 + (1 * 1) + 2];
byte[] crc;
ushort i = 0;
result[i++] = (byte)DevID; // Device ID
result[i++] = (byte)WRITE_COIL_REG; // Command
result[i++] = (byte)(WriteAddr >> 8); // Register Address MSB
result[i++] = (byte)(WriteAddr >> 0); // Register Address LSB
result[i++] = (byte)(1 >> 8); // Count of Register MSB
result[i++] = (byte)(1 >> 0); // Count of Register LSB
result[i++] = (byte)(1 * 1); // Byte Count - [2 * (Num of register)]
result[i++] = (byte)(WriteData >> 0);
crc = GetCRC(result, i);
result[i++] = crc[1]; // CRCH
result[i++] = crc[0]; // CRCL
return result;
}
static public byte[] MakeWriteRegisterData(ushort DevID, ushort WriteAddr, short[] WriteData)
{
byte[] result = new byte[9 + (WriteData.Length * 2)];
byte[] crc;
ushort i = 0;
result[i++] = (byte)DevID; // Device ID
result[i++] = (byte)PRESET_MULTI_REG; // Command
result[i++] = (byte)(WriteAddr >> 8); // Register Address MSB
result[i++] = (byte)(WriteAddr >> 0); // Register Address LSB
result[i++] = (byte)(WriteData.Length >> 8); // Count of Register MSB
result[i++] = (byte)(WriteData.Length >> 0); // Count of Register LSB
result[i++] = (byte)(WriteData.Length * 2); // Byte Count - [2 * (Num of register)]
for (int j = 0; j < WriteData.Length; j++)
{
result[i++] = (byte)(WriteData[j] >> 8);
result[i++] = (byte)(WriteData[j] >> 0);
}
crc = GetCRC(result, i);
result[i++] = crc[1]; // CRCH
result[i++] = crc[0]; // CRCL
return result;
}
static short GetRegister(ushort reg_addr, ref DeviceParamData aParam)
{
short result = 0;
switch (reg_addr)
{
//case 19: result = (short)(0 >> 16); break; // 0021 : UTC TimeStamp MSB
//case 20: result = (short)(58 >> 0); break; // 0022 : UTC TimeStamp LSB
//case 21: result = (short)0x1000; break; // 0023 : Cell Balancing Flag
//case 22: result = (short)0x0000; break; // 0024 : Cell Balancing Voltage
//case 23: result = (short)15; break; // 0024 : Cell Balancing Time
case 0x4002: result = (short)aParam.CellUnderVoltageWarning; break; // 0061 : Low cell voltage warning data
//case 33: result = (short)param.sf1.voltage.CUV_Threshold; break; // 0062 : Low cell voltage protection data
//case 34: result = (short)param.sf1.voltage.CUV_Recovery; break; // 0063 : Low cell voltage recovery data
//case 35: result = (short)param.sf1.voltage.SUV_Warning; break; // 0064 : Low voltage warning data
//case 36: result = (short)param.sf1.voltage.SUV_Threshold; break; // 0065 : Low voltage protection data
//case 37: result = (short)param.sf1.voltage.SUV_Recovery; break; // 0066 : Low voltage recovery data
//case 38: result = (short)param.sf1.voltage.COV_Warning; break; // 0067 : Over cell voltage warning data
//case 39: result = (short)param.sf1.voltage.COV_Threshold; break; // 0068 : Over cell voltage protection data
//case 40: result = (short)param.sf1.voltage.COV_Recovery; break; // 0069 : Over cell voltage recovery data
//case 41: result = (short)param.sf1.voltage.SOV_Warning; break; // 0070 : Over voltage warning data
//case 42: result = (short)param.sf1.voltage.SOV_Threshold; break; // 0071 : Over voltage protection data
//case 43: result = (short)param.sf1.voltage.SOV_Recovery; break; // 0072 : Over voltage recovery data
//case 44: result = (short)param.sf1.temperature.OT_Chg_Warning; break; // 0044 : Charge over temperature warning data
//case 45: result = (short)param.sf1.temperature.OT_Chg_Threshold; break; // 0045 : Charge over temperature protection data
//case 46: result = (short)param.sf1.temperature.OT_Chg_Recovery; break; // 0046 : Charge over temperature recovery data
//case 47: result = (short)param.sf1.temperature.OT_Chg_Time; break; // 0047 : Charge over temperature time
//case 48: result = (short)param.sf1.temperature.OT_Dsg_Warning; break; // 0048 : Discharge over temperature warning data
//case 49: result = (short)param.sf1.temperature.OT_Dsg_Threshold; break; // 0049 : Discharge over temperature protection data
//case 50: result = (short)param.sf1.temperature.OT_Dsg_Recovery; break; // 0050 : Discharge over temperature recovery data
//case 51: result = (short)param.sf1.temperature.OT_Dsg_Time; break; // 0051 : Discharge over temperature time
}
return result;
}
static byte[] ModBusGetRegWordToBytes(ushort addr, ref DeviceParamData aParam)
{
short data;
byte[] result = new byte[2];
data = GetRegister(addr, ref aParam);
result[0] = (byte)(data >> 8);
result[1] = (byte)(data >> 0);
return result;
}
static public byte[] MakeWriteRegisterData(ushort DevID, ushort WriteAddr, ushort reg_len, ref DeviceParamData aParam)
{
int tlen = (reg_len * 2) + 7 + 2;
byte[] result = new byte[tlen];
byte[] tmp;
byte[] crc;
result[0] = (byte)DevID; // Device ID
result[1] = (byte)PRESET_MULTI_REG; // Command
result[2] = (byte)(WriteAddr >> 8); // Register Address MSB
result[3] = (byte)(WriteAddr >> 0); // Register Address LSB
result[4] = (byte)(reg_len >> 8); // Count of Register MSB
result[5] = (byte)(reg_len >> 0); // Count of Register LSB
result[6] = (byte)(reg_len * 2); ; // Current Value MSB
for (int i = 0; i < reg_len; i++)
{
tmp = ModBusGetRegWordToBytes((ushort)(WriteAddr + i),ref aParam);
result[7 + (i * 2) + 0] = tmp[0];
result[7 + (i * 2) + 1] = tmp[1];
}
crc = GetCRC(result, 8);
result[tlen - 2] = crc[0]; // CRCH
result[tlen - 1] = crc[1]; // CRCL
return result;
}
public static byte[] MakeCheckSum(byte[] sData, int offset, int len, bool flag)
{
byte[] result = new byte[2];
int checksum = 0;
for (int i = 0; i < len; i++)
{
checksum += sData[i + offset];
}
checksum = ~checksum + 1;
result[0] = (byte)(checksum >> 8);
result[1] = (byte)checksum;
return result;
}
private static byte[] MakeTxPacket(byte[] sData, int len)
{
string str = "";
byte[] result;
char[] chrArray;
int checksum = 0;
string checksumStr = "";
char[] checksumChr;
str = "~";
for (int i = 0; i < len; i++)
{
str += sData[i].ToString("X2");
}
str += "\r";
chrArray = str.ToCharArray();
for (int i = 0; i < (chrArray.Length - 6); i++)
{
checksum += chrArray[i + 1];
}
checksum = ~checksum + 1;
checksumStr = String.Format("{0:X2}{1:X2}", (byte)(checksum >> 8), (byte)checksum);
checksumChr = checksumStr.ToCharArray();
for (int i = 0; i < 4; i++)
{
chrArray[chrArray.Length - 5 + i] = checksumChr[i];
}
result = new byte[chrArray.Length];
for (int i = 0; i < chrArray.Length; i++)
{
result[i] = (byte)chrArray[i];
}
return result;
}
public static byte[] LengthLchk(int sLen)
{
byte[] result = new byte[2];
int lchksum = 0;
lchksum = (~(((sLen >> 8) & 0xF) +
((sLen >> 4) & 0xF) +
((sLen >> 0) & 0xF)) + 1) % 16;
lchksum = ((lchksum << 12) | sLen);
result[0] = (byte)(lchksum >> 8);
result[1] = (byte)(lchksum >> 0);
return result;
}
public static byte[] MakeTxData(byte addr, byte cmd, int sLen)
{
int buffCh = 0;
byte[] sData;
byte[] lenId;
byte[] checksum;
sData = new byte[((sLen > 0) ? 11 : 10)];
sData[buffCh] = 0x7E; buffCh++; // SOI
sData[buffCh] = 0x25; buffCh++; // VER
sData[buffCh] = addr; buffCh++; // ADDR
sData[buffCh] = 0x46; buffCh++; // CID1
sData[buffCh] = cmd; buffCh++; // CID2 (CMD)
lenId = LengthLchk(sLen); // LENID
sData[buffCh] = lenId[0]; buffCh++; // LENID MSB
sData[buffCh] = lenId[1]; buffCh++; // LENID LSB
if (sLen > 0)
{
sData[buffCh] = (byte)(sLen / 2); buffCh++; // INFO
}
checksum = csSerialCommFunction.MakeCheckSum(sData, 1, sData.Length - 4, false);
sData[buffCh] = checksum[1]; buffCh++;
sData[buffCh] = checksum[0]; buffCh++;
sData[buffCh] = 0x0D; buffCh++; // EOI
return MakeTxPacket(sData, sData.Length);
}
public static int TbPacketCheck(byte[] rdata, int rlen)
{
int result = 0;
byte[] cdata;
byte[] checksum;
byte[] checksum1;
checksum = MakeCheckSum(rdata, 1, rlen - 6, false);
checksum1 = new byte[2];
checksum1[0] = csUtils.StrByte2toByte(rdata[rlen - 4], rdata[rlen - 5]);
checksum1[1] = csUtils.StrByte2toByte(rdata[rlen - 2], rdata[rlen - 3]);
if ((checksum[0] == checksum1[0]) && (checksum[1] == checksum1[1]))
{
cdata = csUtils.StrToByteArray(rdata, 0, rlen);
result = 1;
}
return result;
}
static public int ModbusPacketFromSlaveCheck(byte[] rdata, ushort rlen)
{
int result = 0;
byte[] cdata, crc;
ushort clen, bytecount;
if (rlen > 2)
{
cdata = rdata;
switch (cdata[1])
{
case READ_COIL_STATUS:
case READ_HOLDING_REG:
case READ_INPUT_REG:
bytecount = cdata[2];
clen = (ushort)(bytecount + 5); // header 3, tail 2
if (rlen >= clen)
{
crc = GetCRC(cdata, (ushort)(rlen - 2));
if ((crc[1] == cdata[rlen - 2]) && (crc[0] == cdata[rlen - 1])) result = 1;
else result = -1;
}
break;
case PRESET_MULTI_REG:
case FORCE_SINGLE_COIL:
case PRESET_SINGLE_REG:
clen = 8;
if (rlen >= clen)
{
crc = GetCRC(cdata, (ushort)(rlen - 2));
if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 1;
else result = -1;
}
break;
case ERROR_REG:
clen = 6;
if (rlen >= clen)
{
crc = GetCRC(cdata, (ushort)(rlen - 2));
if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 1;
else result = -1;
}
break;
case FW_FLASH_ERASE_CMD:
clen = 5;
if (rlen >= clen)
{
crc = GetCRC(cdata, (ushort)(rlen - 2));
if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 2;
else result = -1;
}
break;
case FW_FLASH_WRITE_CMD:
clen = 5;
if (rlen >= clen)
{
crc = GetCRC(cdata, (ushort)(rlen - 2));
if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 2;
else result = -1;
}
break;
default:
result = -1;
break;
}
}
return result;
}
public static short[] SerialRxProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref CsDeviceData.DeviceModuleData aModuleData)
{
short[] result = new short[2];
switch (rData[1])
{
case READ_COIL_STATUS:
ReadCoilRegisterProcess(rData, rRegAddr, rLen, ref aModuleData);
break;
case READ_HOLDING_REG:
ReadHoldRegisterProcess(rData, rRegAddr, rLen, ref aModuleData);
break;
case READ_INPUT_REG:
ReadInputRegisterProcess(rData, rRegAddr, rLen, ref aModuleData);
break;
//case READ_INPUT_REG:
// ReadRegister(rData, rRegAddr, rLen, ref rSystemData);
// break;
case PRESET_MULTI_REG:
// read_holding_reg_process(reverse16(rsp->start_addr, true), reverse16(rsp->qty_reg, true));
//result[0] = 1;
//result[1] = 1;
break;
case ERROR_REG:
result[0] = 2;
result[1] = (short)((rData[0] << 8) | rData[1]);
break;
}
return result;
}
private static void ReadCoilRegisterProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref CsDeviceData.DeviceModuleData aModuleData)
{
// 기본 유효성 검사
if (rData == null || rData.Length < 3)
{
// TODO: 로그/에러 처리 - 응답 길이 부족(DevID, Func, ByteCount 최소 필요)
return;
}
int i = 2; // rData[0]=DevID, rData[1]=Func(0x01), rData[2]=ByteCount
int byteCount = rData[i++];
if (byteCount < 0) // byte → int 승격 시 의미 없지만 방어적 체크
{
// TODO: 로그/에러 처리 - ByteCount 음수
return;
}
// 바이트 카운트만큼의 데이터가 실제로 존재하는지 확인
if (rData.Length < i + byteCount)
{
// TODO: 로그/에러 처리 - 실제 데이터가 ByteCount보다 짧음
return;
}
// 파싱할 수 있는 최대 코일 수와 요청한 코일 수 중 작은 쪽으로 제한
int coilsAvailable = byteCount * 8;
int coilsToParse = Math.Min(coilsAvailable, rLen);
if (coilsToParse <= 0)
{
// TODO: 로그/에러 처리 - 파싱할 코일 없음
return;
}
// Modbus Coils는 LSB-first: 각 바이트의 bit0이 가장 먼저 오는 코일 상태
for (int bit = 0; bit < coilsToParse; bit++)
{
int byteIndex = i + (bit / 8);
int bitPos = bit % 8;
// 방어적 인덱스 검사 (이론상 위의 길이검사로 안전하지만 이중 방어)
if (byteIndex < 0 || byteIndex >= rData.Length)
{
// TODO: 로그/에러 처리 - 계산된 인덱스가 범위를 벗어남
break;
}
int val = (rData[byteIndex] >> bitPos) & 0x01;
try
{
SetCoilRegister((short)(rRegAddr + bit), (short)val, ref aModuleData);
}
catch
{
// TODO: 로그/에러 처리 - 개별 레지스터 반영 실패(계속 진행)
}
}
}
private static void ReadHoldRegisterProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref CsDeviceData.DeviceModuleData aModuleData)
{
int i, j;
short reg_count;
short reg_value;
i = 2;
reg_count = (short)(rData[i] / 2); i += 1;
for (j = 0; j < reg_count; j++)
{
reg_value = (short)(rData[i] << 8 | rData[i + 1]);
SetHoldRegister((short)(rRegAddr + j), reg_value, ref aModuleData);
i += 2;
}
}
private static void ReadInputRegisterProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref CsDeviceData.DeviceModuleData aModuleData)
{
int i, j;
short reg_count;
short reg_value;
i = 2;
reg_count = (short)(rData[i] / 2); i += 1;
for (j = 0; j < reg_count; j++)
{
reg_value = (short)(rData[i] << 8 | rData[i + 1]);
SetInputRegister((short)(rRegAddr + j), reg_value, ref aModuleData);
i += 2;
}
}
private static void SetInputRegister(short reg_addr, short reg_value, ref CsDeviceData.DeviceModuleData aModuleData)
{
switch (reg_addr)
{
case 1: MakeMaxAvgMinCellVoltage(ref aModuleData); break;
case 2: MakeMaxAvgMinTemperature(ref aModuleData); break;
case 45: break;
}
}
private static void SetCoilRegister(short reg_addr, short reg_value, ref CsDeviceData.DeviceModuleData aModuleData)
{
switch (reg_addr)
{
case 0x3078:
aModuleData.StatusData.relayStatus = (ushort)reg_value;
aModuleData.CalibrationData.FetCalib.FetStatus = reg_value;
break;
case 0x502E:
aModuleData.CalibrationData.Current.ChargeOption = reg_value;
break;
}
}
private static void SetHoldRegister(short reg_addr, short reg_value, ref CsDeviceData.DeviceModuleData aModuleData)
{
uint temp = 0;
switch (reg_addr)
{
case 0: aModuleData.ValueData.voltage = (short)(reg_value / 10); break; //Total Voltage
case 1: aModuleData.ValueData.current = (short)(reg_value / 10); break; //Total Current
case 2: // Cell Voltage #1
case 3: // Cell Voltage #2
case 4: // Cell Voltage #3
case 5: // Cell Voltage #4
case 6: // Cell Voltage #5
case 7: // Cell Voltage #6
case 8: // Cell Voltage #7
case 9: // Cell Voltage #8'
case 10: // Cell Voltage #9
case 11: // Cell Voltage #10
case 12: // Cell Voltage #11
case 13: // Cell Voltage #12
case 14: // Cell Voltage #13
case 15: // Cell Voltage #14
case 16: // Cell Voltage #15
aModuleData.ValueData.CellVoltage[reg_addr - 2] = (ushort)(reg_value / 1);
MakeMaxAvgMinCellVoltage(ref aModuleData);
break; // 15 CellVoltage 1mV
case 17: break; // Cell Voltage #16 - Reserved
case 18: aModuleData.ValueData.MosTemperature = (short)((reg_value) * 10); break; //Ext1 Temperature (Temp of MOS-FET)
case 19: aModuleData.ValueData.AmbTemperature = (short)((reg_value) * 10); break; //Ext2 Amb. PCB Temperature 1C
case 20: break; // Temp Max.
case 21: aModuleData.ValueData.remainingCapacity = (short)(reg_value / 1); break; // Remaining Capacity
case 22: aModuleData.ValueData.MaxBattChgCurr = reg_value / 1; break;
case 23: aModuleData.ValueData.SOH = (short)(reg_value * 10); break;
case 24: aModuleData.ValueData.SOC = (short)(reg_value * 10); break; //SOC
case 25: aModuleData.StatusData.status = (ushort)reg_value; break; //Operating Status
case 26:
aModuleData.StatusData.warning = (ushort)reg_value;
if ((aModuleData.StatusData.specialAlarm & 0x0004) != 0)
aModuleData.StatusData.warning |= 0x4000;
else
aModuleData.StatusData.warning &= 0xBFFF;
break; //Warning Status
case 27: aModuleData.StatusData.protect = (ushort)reg_value; break; //Protection Status
case 28: // Error Code
// 0x0001Voltage error
// 0x0002Temperature error
// 0x0004: Current Check Error
// 0x0010Cell unbalance
break;
case 29: // Cycle count MSB
temp = aModuleData.ValueData.cycleCount;
aModuleData.ValueData.cycleCount = (temp & (0x0000FFFF)) | ((uint)reg_value << 16);
break;
case 30: // Cycle count LSB
temp = aModuleData.ValueData.cycleCount;
aModuleData.ValueData.cycleCount = (temp & (0xFFFF0000)) | ((uint)reg_value << 0);
break;
case 31: // fullChargeCapacity MSB
temp = aModuleData.ValueData.fullChgCapacity_Ah;
aModuleData.ValueData.fullChgCapacity_Ah = (temp & (0x0000FFFF)) | ((uint)reg_value << 16);
break;
case 32: // fullChargeCapacity LSB
temp = aModuleData.ValueData.fullChgCapacity_Ah;
aModuleData.ValueData.fullChgCapacity_Ah = (temp & (0xFFFF0000)) | ((uint)reg_value << 0);
break;
case 33:
case 34:
aModuleData.ValueData.CellTemperature[((reg_addr - 33) * 2) + 0] = (short)(((reg_value >> 8) & 0xFF) * 10);
aModuleData.ValueData.CellTemperature[((reg_addr - 33) * 2) + 1] = (short)(((reg_value >> 0) & 0xFF) * 10);
MakeMaxAvgMinTemperature(ref aModuleData);
break;
case 35: break; // Reserved
case 36: aModuleData.cellQty = reg_value; break; // Cell Qty
case 37: aModuleData.ValueData.designedCapacity = reg_value; break;
case 38: aModuleData.StatusData.cellBallanceStatus = (ushort)reg_value; break;
case 39: aModuleData.StatusData.specialAlarm = (ushort)(reg_value); break; // Special Alarm
//case 61: aModuleData.StatusData.cellBallanceStatus = reg_value; break;
//45 ~ 99 : Reserved
case 45: aModuleData.BmsDateTimeShort1 = (ushort)reg_value; break; // DateTime
case 46: aModuleData.BmsDateTimeShort2 = (ushort)reg_value;
int yy, MM, dd, HH, mm, ss;
aModuleData.BmsDateTimeInt = (aModuleData.BmsDateTimeShort1 << 16) | (aModuleData.BmsDateTimeShort2);
yy = (aModuleData.BmsDateTimeInt >> 26) & 0x003F;
MM = ((aModuleData.BmsDateTimeInt >> 22) & 0x000F) % 13;
dd = ((aModuleData.BmsDateTimeInt >> 17) & 0x001F) % 32;
HH = ((aModuleData.BmsDateTimeInt >> 12) & 0x001F) % 24;
mm = ((aModuleData.BmsDateTimeInt >> 6) & 0x003F) % 60;
ss = ((aModuleData.BmsDateTimeInt >> 0) & 0x003F) % 60;
yy += 2000;
aModuleData.BmsDateTime.DateTimeStr = string.Format("{0:0000}-{1:00}-{2:00} {3:00}:{4:00}:{5:00}"
, yy
, MM
, dd
, HH
, mm
, ss
);
break; // DateTime
case 47: aModuleData.CalibrationData.ChaMode.Mode = reg_value; break; // 0x2F
case 48: aModuleData.CalibrationData.ChaMode.Value = reg_value; break; // 0x2F
//case 56: aModuleData.CalibrationData.BalCalib.Volt = reg_value; break; // Cell Balance Voltage
//case 57: aModuleData.CalibrationData.BalCalib.Diff = reg_value; break; // Cell Balance Diff
case 58: aModuleData.ParamData.LowSocWarning = reg_value; break;
case 61: aModuleData.ParamData.CellUnderVoltageWarning = reg_value; break;
case 62: aModuleData.ParamData.CellUnderVoltageTrip = reg_value; break;
case 63: aModuleData.ParamData.CellUnderVoltageRelease = reg_value; break;
case 64: aModuleData.ParamData.SysUnderVoltageWarning = (short)(reg_value / 10); break;
case 65: aModuleData.ParamData.SysUnderVoltageTrip = (short)(reg_value / 10); break;
case 66: aModuleData.ParamData.SysUnderVoltageRelease = (short)(reg_value / 10); break;
case 67: aModuleData.ParamData.CellOverVoltageWarning = reg_value; break;
case 68: aModuleData.ParamData.CellOverVoltageTrip = reg_value; break;
case 69: aModuleData.ParamData.CellOverVoltageRelease = reg_value; break;
case 70: aModuleData.ParamData.SysOverVoltageWarning = (short)(reg_value / 10); break;
case 71: aModuleData.ParamData.SysOverVoltageTrip = (short)(reg_value / 10); break;
case 72: aModuleData.ParamData.SysOverVoltageRelease = (short)(reg_value / 10); break;
case 76: aModuleData.ParamData.ChaOverCurrentTimes = (short)(reg_value / 1); break;
case 77: aModuleData.ParamData.DchOverCurrentTimes = (short)(reg_value / 1); break;
case 78: aModuleData.ParamData.ChaOverCurrentReleaseTime = (short)(reg_value * 1); break;
case 79: aModuleData.ParamData.DchOverCurrentReleaseTime = (short)(reg_value * 1); break;
case 80: aModuleData.ParamData.ChaOverCurrentTrip1 = (short)(reg_value / 10); break;
case 81: aModuleData.ParamData.DchOverCurrentTrip1 = (short)(reg_value / 10); break;
case 82: aModuleData.ParamData.ShortCircuit = (short)(reg_value / 10); break; // Short Circuit Current = 300A
case 83: aModuleData.ParamData.ChaOverCurrentTrip2 = (short)(reg_value / 10); break;
case 84: aModuleData.ParamData.DchOverCurrentTrip2 = (short)(reg_value / 10); break;
case 85: aModuleData.ParamData.ChaOverCurrentDelay1 = (short)(reg_value / 1); break;
case 86: aModuleData.ParamData.ChaOverCurrentDelay2 = (short)(reg_value / 1); break;
case 87: aModuleData.ParamData.DchOverCurrentDelay1 = (short)(reg_value / 1); break;
case 88: aModuleData.ParamData.DchOverCurrentDelay2 = (short)(reg_value / 1); break;
case 90: aModuleData.ParamData.ChaLowTempWarning = (short)(reg_value - 50); break;
case 91: aModuleData.ParamData.ChaLowTempTrip = (short)(reg_value - 50); break;
case 92: aModuleData.ParamData.ChaLowTempRelease = (short)(reg_value - 50); break;
case 93: aModuleData.ParamData.ChaHighTempWarning = (short)(reg_value - 50); break;
case 94: aModuleData.ParamData.ChaHighTempTrip = (short)(reg_value - 50); break;
case 95: aModuleData.ParamData.ChaHighTempRelease = (short)(reg_value - 50); break;
case 96: aModuleData.ParamData.DchLowTempWarning = (short)(reg_value - 50); break;
case 97: aModuleData.ParamData.DchLowTempTrip = (short)(reg_value - 50); break;
case 98: aModuleData.ParamData.DchLowTempRelease = (short)(reg_value - 50); break;
case 99: aModuleData.ParamData.DchHighTempWarning = (short)(reg_value - 50); break;
case 100: aModuleData.ParamData.DchHighTempTrip = (short)(reg_value - 50); break;
case 101: aModuleData.ParamData.DchHighTempRelease = (short)(reg_value - 50); break;
case 102: break; // PCB High Temp Warning
case 103: break; // PCB High Temp Trip
case 104: break; // PCB High Temp Release
//100 ~111 : Model_Product Name
case 105:
case 106:
case 107:
case 108:
case 109:
case 110:
case 111:
case 112:
case 113:
case 114:
case 115:
case 116:
int mReg = reg_addr - 105;
aModuleData.Information.Model_Byte[(mReg * 2) + 0] = (byte)(reg_value >> 8);
aModuleData.Information.Model_Byte[(mReg * 2) + 1] = (byte)(reg_value >> 0);
if (reg_addr == 116)
{
aModuleData.Information.ModelName = Encoding.Default.GetString(aModuleData.Information.Model_Byte).Trim('\0');
}
break;
//112 ~114 : FW Version
case 117:
case 118:
case 119:
int fReg = reg_addr - 117;
aModuleData.Information.FwVer_Byte[(fReg * 2) + 0] = (byte)(reg_value >> 8);
aModuleData.Information.FwVer_Byte[(fReg * 2) + 1] = (byte)(reg_value >> 0);
if (reg_addr == 119)
{
aModuleData.Information.SwProductRev = Encoding.Default.GetString(aModuleData.Information.FwVer_Byte).Trim('\0');
}
break;
//115 ~ 122 : BMS Serial number
case 120:
case 121:
case 122:
case 123:
case 124:
case 125:
case 126:
case 127:
int snReg = reg_addr - 120;
aModuleData.Information.BMS_SN[(snReg * 2) + 0] = (byte)(reg_value >> 8);
aModuleData.Information.BMS_SN[(snReg * 2) + 1] = (byte)(reg_value >> 0);
if (reg_addr == 127)
{
aModuleData.Information.HwSerialNumber = Encoding.Default.GetString(aModuleData.Information.BMS_SN).Trim('\0');
}
break;
case 130: aModuleData.ParamData.EnvLowTempWarning = (short)(reg_value - 50); break;
case 131: aModuleData.ParamData.EnvLowTempTrip = (short)(reg_value - 50); break;
case 132: aModuleData.ParamData.EnvLowTempRelease = (short)(reg_value - 50); break;
case 133: aModuleData.ParamData.EnvHighTempWarning = (short)(reg_value - 50); break;
case 134: aModuleData.ParamData.EnvHighTempTrip = (short)(reg_value - 50); break;
case 135: aModuleData.ParamData.EnvHighTempRelease = (short)(reg_value - 50); break;
case 136: // Anti-Theft Communication
aModuleData.CalibrationData.AntiTheft.Comm = reg_value;
break;
case 137: // Anti-Theft Gyro-Scope
aModuleData.CalibrationData.AntiTheft.GyroScope = reg_value;
break;
case 163: // 0xA3
case 164: // 0xA4
case 165: // 0xA5
case 166: // 0xA6
int ManuDateReg = reg_addr - 163;
aModuleData.Information.ManuDate_Byte[(ManuDateReg * 2) + 0] = (byte)(reg_value >> 8);
aModuleData.Information.ManuDate_Byte[(ManuDateReg * 2) + 1] = (byte)(reg_value >> 0);
if (reg_addr == 166)
{
aModuleData.Information.ManufacturingDate = Encoding.Default.GetString(aModuleData.Information.ManuDate_Byte).Trim('\0');
}
break;
}
csMakeDataFunction.MakeAlarm(ref aModuleData);
}
public static void MakeMaxAvgMinCellVoltage(ref CsDeviceData.DeviceModuleData aModuleData)
{
int Max, Avg, Min, Sum;
int MaxNo, MinNo;
Max = Avg = Min = Sum = 0;
MaxNo = MinNo = 0;
for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_CELL_SIZE; i++)
{
if (i == 0)
{
Max = Min = aModuleData.ValueData.CellVoltage[i];
}
Sum += aModuleData.ValueData.CellVoltage[i];
if (Max < aModuleData.ValueData.CellVoltage[i])
{
Max = aModuleData.ValueData.CellVoltage[i];
MaxNo = i;
}
if (Min > aModuleData.ValueData.CellVoltage[i])
{
Min = aModuleData.ValueData.CellVoltage[i];
MinNo = i;
}
}
Avg = Sum / csConstData.SystemInfo.MAX_MODULE_CELL_SIZE;
aModuleData.AvgData.avgCellVoltage = (short)Avg;
aModuleData.AvgData.maxCellVoltage = (short)Max;
aModuleData.AvgData.maxCellNum = (short)(MaxNo + 1);
aModuleData.AvgData.minCellVoltage = (short)Min;
aModuleData.AvgData.minCellNum = (short)(MinNo + 1);
aModuleData.AvgData.diffCellVoltage = (short)(Max - Min);
}
private static void MakeMaxAvgMinTemperature(ref CsDeviceData.DeviceModuleData aModuleData)
{
int Max, Avg, Min, Sum;
int MaxNo, MinNo;
Max = Avg = Min = Sum = 0;
MaxNo = MinNo = 0;
//for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE; i++)
for (int i = 0; i < 4; i++)
{
if (i == 0)
{
Max = Min = aModuleData.ValueData.CellTemperature[i];
}
Sum += aModuleData.ValueData.CellTemperature[i];
if (Max < aModuleData.ValueData.CellTemperature[i])
{
Max = aModuleData.ValueData.CellTemperature[i];
MaxNo = i;
}
if (Min > aModuleData.ValueData.CellTemperature[i])
{
Min = aModuleData.ValueData.CellTemperature[i];
MinNo = i;
}
}
//Avg = Sum / csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE;
Avg = Sum / 4;
aModuleData.AvgData.avgTemp = (short)Avg;
aModuleData.AvgData.maxTemp = (short)Max;
aModuleData.AvgData.maxTempNum = (short)(MaxNo + 1);
aModuleData.AvgData.minTemp = (short)Min;
aModuleData.AvgData.minTempNum = (short)(MinNo + 1);
aModuleData.AvgData.diffTemp = (short)(Max - Min);
}
public static short MakeUartWarningData(short rdata)
{
short result = 0;
bool[] bAlarm = csUtils.Int16ToBitArray(rdata);
if (bAlarm[0] == true) result |= (short)(1 << 2); // 0x0001Pack OV
if (bAlarm[1] == true) result |= (short)(1 << 4); // 0x0002Cell OV
if (bAlarm[2] == true) result |= (short)(1 << 3); // 0x0004Pack UV
if (bAlarm[3] == true) result |= (short)(1 << 5); // 0x0008Cell UV
if (bAlarm[4] == true) result |= (short)(1 << 6); // 0x0010Charging OC
if (bAlarm[5] == true) result |= (short)(1 << 7); // 0x0020Discharging OC
if (bAlarm[8] == true) result |= (short)(1 << 0); // 0x0080: Charging Over Tempratuer
if (bAlarm[9] == true) result |= (short)(1 << 0); // 0x0080: Discharging Over Tempratuer
if (bAlarm[10] == true) result |= (short)(1 << 1); // 0x0040: Charging Under Tempratuer
if (bAlarm[11] == true) result |= (short)(1 << 1); // 0x0040: Discharging Under Tempratuer
if (bAlarm[12] == true) result |= (short)(1 << 11); // 0x0200SOC Low
return result;
}
public static short MakeUartTripData(short rdata)
{
short result = 0;
bool[] bAlarm = csUtils.Int16ToBitArray(rdata);
if (bAlarm[0] == true) result |= (short)(1 << 2); // 0x0001Pack OV
if (bAlarm[1] == true) result |= (short)(1 << 4); // 0x0002Cell OV
if (bAlarm[2] == true) result |= (short)(1 << 3); // 0x0004Pack UV
if (bAlarm[3] == true) result |= (short)(1 << 5); // 0x0008Cell UV
if (bAlarm[4] == true) result |= (short)(1 << 6); // 0x0010Charging OC
if (bAlarm[5] == true) result |= (short)(1 << 7); // 0x0020Discharging OC
if (bAlarm[8] == true) result |= (short)(1 << 0); // 0x0080: Charging Over Tempratuer
if (bAlarm[9] == true) result |= (short)(1 << 0); // 0x0080: Discharging Over Tempratuer
if (bAlarm[10] == true) result |= (short)(1 << 1); // 0x0040: Charging Under Tempratuer
if (bAlarm[11] == true) result |= (short)(1 << 1); // 0x0040: Discharging Under Tempratuer
if (bAlarm[13] == true) result |= (short)(1 << 9); // 0x0200Short Circuit Protection
return result;
}
private static short MakeUartErrorData(short rdata, short cdata)
{
short result = cdata;
bool[] bAlarm = csUtils.Int16ToBitArray(rdata);
if (bAlarm[0] == true) result |= (short)(1 << 9); // 0x0001Voltage error
if (bAlarm[1] == true) result |= (short)(1 << 9); // 0x0002Temperature error
if (bAlarm[2] == true) result |= (short)(1 << 9); // 0x0004: 电流检测Error
if (bAlarm[3] == true) result |= (short)(1 << 9); // 0x0010Cell unbalance
return result;
}
}
}