C#-DL/T 645—2007协议
前面一篇写了97版的协议,今天就来看下07版的DL/T 645协议,总的来说,差别不是很大,也是就是数据项标识的不同。
1. 帧格式
帧格式是和之前97的一版是一样的,
注意:
(1)97一版忘了说,地址域是BCD码,若电表地址是112233445566,那么传输的字节就是0x66 0x55 0x44 0x33 0x22 0x11,即小端传输;
(2)数据标识项与97的有差别,97的是两个字节,07的是4个字节,如图所示DI3 DI2 DI2 DI0;
(3)依然要发送4个字节的FEH,来唤醒对方;
(4)传输+-0x33的如图更加详细,即发送方+0x33后发送,接收方收到数据后-0x33进行处理;
2. 数据项标识
这次数据项标识采用发送请求块的方式进行请求数据,比如ABC相电压,只发送一次请求即可返回三相电压。
如图所示可以请求00 01 FF 00正向有功电能数据块的数据,对方会把包含的所有数据都会返回,文档上写的是63个电能,实际上大多数电表是没有的,所以不用太计较那么多的数据,一般就是尖峰平谷4段。
3. 数据库表,依然采用初始化数据表配置的方式进行处理(其实是先写的07版的协议...)
DROP TABLE IF EXISTS `protocol_DLT645_07package`;
CREATE TABLE `protocol_DLT645_07package` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`devicetype` int(11) NOT NULL, -- 设备类型
`blockaddr` int(11) NOT NULL, -- 块地址
`blockname` varchar(50) NOT NULL, -- 块名称
`blockcontent` varchar(50) NOT NULL, -- 块内容
`visible` int(11) NOT NULL, -- 是否请求;0不请求;1请求;
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '130816', '正向有功总电能数据块', '65536, 65792, 66048, 66304, 66560', '1'); --0001FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '196352', '反向有功总电能数据块', '131072, 131328, 131584, 131840, 132096', '1'); --0002FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33685248', 'ABC相电压数据块', '33620224, 33620480, 33620736', '1'); --0201FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33750784', 'ABC相电流数据块', '33685760, 33686016, 33686272', '1'); --0202FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33816320', '瞬时总有功功率数据块', '33751040, 33751296, 33751552, 33751808', '1'); --0203FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33881856', '瞬时总无功功率数据块', '33816576, 33816832, 33817088, 33817344', '1'); --0204FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33947392', '瞬时总视在功率数据块', '33882112, 33882368, 33882624, 33882880', '1'); --0205FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '34012928', '总功率因数数据块', '33947648, 33947904, 33948160, 33948416', '1'); --0206FF00
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '41943042', '电网频率数据', '41943042', '1'); --02800002
INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '41943048', '时钟电池电压', '41943048', '1'); --02800008
DROP TABLE IF EXISTS `protocol_DLT645_07signal`;
CREATE TABLE `protocol_DLT645_07signal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`devicetype` int(11) NOT NULL, -- 设备类型
`signaladdr` int(11) NOT NULL, -- 信号地址
`signalname` varchar(50) NOT NULL, -- 信号名称
`signalid` int(11) NOT NULL, -- 信号ID
`datalength` int(11) NOT NULL, -- 数据长度,所占字节数
`ratio` float NOT NULL, -- 变比
`ismultiplifct` int(11) NOT NULL, -- 是否乘于互感器变比,变比在协议中配置
`visible` int(11) NOT NULL, -- 是否需要解析;0不解析;1解析;
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '65536', '正向有功总电能', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '65792', '(当前)正向有功费率1电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66048', '(当前)正向有功费率2电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66304', '(当前)正向有功费率3电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66560', '(当前)正向有功费率4电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131072', '反向有功总电能', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131328', '(当前)反向有功费率1电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131584', '(当前)反向有功费率2电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131840', '(当前)反向有功费率3电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '132096', '(当前)反向有功费率4电量', '-1', '4', '0.01', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620224', 'A相电压', '-1', '2', '0.1', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620480', 'B相电压', '-1', '2', '0.1', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620736', 'C相电压', '-1', '2', '0.1', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33685760', 'A相电流', '-1', '3', '0.001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33686016', 'B相电流', '-1', '3', '0.001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33686272', 'C相电流', '-1', '3', '0.001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751040', '瞬时总有功功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751296', '瞬时A相有功功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751552', '瞬时B相有功功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751808', '瞬时C相有功功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33816576', '瞬时总无功功率', '-1', '3', '0.0001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33816832', '瞬时A相无功功率', '-1', '3', '0.0001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33817088', '瞬时B相无功功率', '-1', '3', '0.0001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33817344', '瞬时C相无功功率', '-1', '3', '0.0001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882112', '瞬时总视在功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882368', '瞬时A相视在功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882624', '瞬时B相视在功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882880', '瞬时C相视在功率', '-1', '3', '0.0001', '1', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33947648', '总功率因数', '-1', '2', '0.001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33947904', 'A相功率因数', '-1', '2', '0.001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33948160', 'B相功率因数', '-1', '2', '0.001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33948416', 'C相功率因数', '-1', '2', '0.001', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '41943042', '电网频率', '-1', '2', '0.01', '0', '1' );
INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '41943048', '时钟电池电压', '-1', '2', '0.01', '0', '1' );
protocol_DLT645_07package表示请求的数据块表,主要是对应了请求块和应答包之间的关系。用的是十进制,只把请求块的内容又转换成了十六进制,可以对照协议文档进行查找;
另外,07版的我是取用的+0x33之后的数据,07版本我是取用的原有数据的标识,可能会更加清晰;
4. 上代码,环境和97版的是一样的,
初始化配置项:
/// <summary>
/// 电表物理地址
/// </summary>
public byte[] MeterPhysicalAddr { set; get; }
/// <summary>
/// 请求实时数据,块
/// </summary>
public Dictionary<int, int[]> RequestRealDataDic { set; get; }
/// <summary>
/// 信号ID MAP
/// </summary>
public Dictionary<int, Signal> SignalIdMap { set; get; }
初始化请求包:
/// <summary>
/// 初始化请求实时数据,块
/// </summary>
private void InitRequestRealDataDic()
{
RequestRealDataDic = new Dictionary<int, int[]>();
List<protocol_dlt645package> pcakageS = DbHelp.GetList<protocol_dlt645package>().
Where(s => s.visible == (int)EnumYesOrNo.Yes).
Where(s => s.devicetype == this.DeviceType).ToList();
if(pcakageS == null || pcakageS.Any() == false)
{
return;
}
foreach(protocol_dlt645package package in pcakageS)
{
string[] siganlAddrS = package.blockcontent.Split(' ', ',', ',').Where(s => !string.IsNullOrEmpty(s)).ToArray();
int[] signalAddrList = Array.ConvertAll(siganlAddrS, int.Parse);
if (signalAddrList != null && signalAddrList.Count() != 0)
{
RequestRealDataDic.Add(package.blockaddr, signalAddrList);
}
}
}
初始化解析数据包:
/// <summary>
/// 初始化信号ID MAP
/// </summary>
private void InitSignalIdMap()
{
SignalIdMap = new Dictionary<int, Signal>();
List<protocol_dlt645signal> signalList = DbHelp.GetList<protocol_dlt645signal>().Where(x => x.devicetype == this.DeviceType).ToList();
if (signalList == null || signalList.Any() == false)
{
return;
}
foreach(protocol_dlt645signal dlt645signal in signalList)
{
Signal signal = new Signal
{
SignalID = dlt645signal.signalid,
SignalName = dlt645signal.signalname,
DataLength = dlt645signal.datalength,
Visible = dlt645signal.visible,
Ratio = dlt645signal.ismultiplifct == (int)EnumYesOrNo.Yes ? dlt645signal.ratio*ConstValue.FCT : dlt645signal.ratio,
};
SignalIdMap.Add(dlt645signal.signaladdr, signal);
}
}
初始化电表地址等:
/// <summary>
/// 初始化属性
/// </summary>
private void InitAttribute()
{
try
{
MeterPhysicalAddr = new byte[6];
var addr = ConfigurationManager.AppSettings["MeterPhysicalAddr"];
if (addr != null)
{
string[] strList = addr.Split('|');
for (int i = 0; i < 6; i++)
{
MeterPhysicalAddr[i] = BCD_to_HEX(byte.Parse(strList[5 - i]));
}
}
}
catch(Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
}
}
两个线程一发一收,我们这里用到了redis当做消息队列处理,收发都是经过redis进行处理的,可以理解为当前的发送不是直接到设备的,而是经过一层统一处理放到redis的消息队列当中,相当于收发都取redis的,这个不重要,和直连是一样的。
发送请求实时数据线程:
/// <summary>
/// 按块请求实时数据
/// </summary>
private void RequestBlockThread()
{
while (true)
{
Thread.Sleep(RealDataInterval);
try
{
foreach (int dataFlag in RequestRealDataDic.Keys)
{
Thread.Sleep(RealDataInterval);
// 发送实时数据请求
SendDataRequest(dataFlag);
// 有功功率请求频繁
//Thread.Sleep(RealDataInterval);
//SendDataRequest(ConstValue.ActivePowerFlag);
}
}
catch (Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
}
}
}
/// <summary>
/// 发送实时数据请求
/// </summary>
/// <param name="dataFlag"></param>
private void SendDataRequest(int dataFlag)
{
MessageInfo sendMessage = new MessageInfo
{
MessageHead = ConstValue.MessageHead,
Addr = MeterPhysicalAddr, // 改为自动获取或
StartHead = ConstValue.MessageHead,
ControlCode = ConstValue.ControlCode,
DataLength = ConstValue.DataFlagLength,
DataFlag = ConvertDataFlag(dataFlag, EnumAddDataFlag.Add),
EndFrame = ConstValue.MessageEndFrame
};
SaveSendMessage(sendMessage);
}
/// <summary>
/// 转换数据标识,-+0x33
/// </summary>
/// <param name="dataFlag"></param>
/// <param name="addFlag"></param>
/// <returns></returns>
private int ConvertDataFlag(int dataFlag, EnumAddDataFlag addFlag)
{
byte[] dataS = new byte[4];
ConvertIntToByteArray(dataFlag, ref dataS);
if (addFlag == EnumAddDataFlag.Add)
{
for (int i = 0; i < 4; i++)
{
dataS[i] += ConstValue.DataFlagDeviation;
}
}
else
{
for (int i = 0; i < 4; i++)
{
dataS[i] -= ConstValue.DataFlagDeviation;
}
}
int index = 0;
return DataCopy.GetINT(dataS, ref index);
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="message"></param>
private void SaveSendMessage(MessageInfo message)
{
try
{
byte[] SendData = message.ObjectToByte();
LogEvent.LogInfo.FatalFormat("发送:\r\n{0}", DataCopy.ToHexString(SendData));
RedisHelper redisclient = new RedisHelper((int)EnumUserRedisNum.Protocol);
string sessionId = redisclient.HashGetString(ConstValue.DeviceCodeSessionKey, string.Format("{0}|{1}", StationID, CanID));
SendMessage sendMessage = new SendMessage();
sendMessage.SessionID = sessionId;
sendMessage.SendData = SendData;
redisclient.ListRightPush(String.Format("{0}|发送", ProtocolMeterHelp.ProtocolID), sendMessage);
}
catch (Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
}
}
接收实时数据应答线程:
/// <summary>
/// 获取消息线程
/// </summary>
private void GetMessageTh()
{
RedisHelper redisclient = new RedisHelper((int)EnumUserRedisNum.Protocol);
string key = String.Format("{0}|接收", ProtocolID);
ProtocolMeter ProtocolMeter = ProtocolMeter.GetInstance();
while (true)
{
Thread.Sleep(RequestInterval * 100);
try
{
if (Work == false)
{
continue;
}
ReviceMessage message = redisclient.ListLeftPop<ReviceMessage>(key);
if (message == null)
{
continue;
}
ProtocolMeter = ProtocolMeter.GetInstance();
ProtocolMeter.ParseProtocol(message);
}
catch(Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
}
}
}
/// <summary>
/// 解析数据包
/// </summary>
/// <param name="rMsg"></param>
public void ParseProtocol(ReviceMessage rMsg)
{
try
{
SaveClientStatus(rMsg);
if (rMsg.Key == EnumSocektKeyType.连接.ToString())
{
LogEvent.LogInfo.Debug("**************************客户端连接**************************");
// 保存设备、局站、协议等、
StationLogin(rMsg.SessionID);
return;
}
//
LogEvent.LogInfo.DebugFormat("接收:\r\n{0}", DataCopy.ToHexString(rMsg.ReviceData));
MessageInfo messageInfo = new MessageInfo(rMsg);
if (!messageInfo.Valid)
{
MessageRecord.SaveInvalidMessage(rMsg.ReviceData); //记录非法数据包
return;
}
// 数据解析
ReviceRealData(messageInfo.Data, messageInfo.DataFlag);
}
catch (Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
}
}
/// <summary>
/// 接收到实时数据
/// </summary>
/// <param name="data">数据域</param>
/// <param name="dataFlag">数据标识</param>
private void ReviceRealData(byte[] data, int dataFlag)
{
int flag = ConvertDataFlag(dataFlag, EnumAddDataFlag.Reduce); // 减0x33
SaveRealData(flag, data);
}
/// <summary>
/// 保存实时数据
/// </summary>
/// <param name="dataFlag"></param>
/// <param name="data"></param>
private void SaveRealData(int dataFlag, byte[] data)
{
List<RealDataInfo> realList = new List<RealDataInfo>();
Dictionary<int, byte[]> dataByteDic = new Dictionary<int, byte[]>();
int index = 0;
int[] dataFlagS = RequestRealDataDic[dataFlag];
foreach(int flag in dataFlagS)
{
int dstOffset = 0;
byte[] bS = new byte[SignalIdMap[flag].DataLength];
DataCopy.ByteCopy(data, index, bS, ref dstOffset, data.Length, SignalIdMap[flag].DataLength);
index += SignalIdMap[flag].DataLength;
dataByteDic.Add(flag, bS);
}
LogEvent.LogInfo.FatalFormat("dataByteDic---{0}", dataByteDic.Keys.Count);
foreach (int flag in dataByteDic.Keys)
{
if(SignalIdMap[flag].Visible == (int)EnumYesOrNo.No)
{
continue;
}
int count = dataByteDic[flag].Length;
double value = 0;
int minus_flag = 0;
if((((dataByteDic[flag][count-1] - ConstValue.DataFlagDeviation) >> 7) & 0x01) == 1)
{
minus_flag = 1;
}
value += HEX_to_BCD((byte)((dataByteDic[flag][count - 1] - ConstValue.DataFlagDeviation) & 0x7F)) * Math.Pow(10, (count - 1) * 2);
for (int i = 0; i < count - 1; i++)
{
value += HEX_to_BCD((byte)(dataByteDic[flag][i] - ConstValue.DataFlagDeviation)) * Math.Pow(10, i * 2);
}
if(minus_flag == 1)
{
value = -value;
}
realList.Add(new RealDataInfo
{
DeviceCode = string.Format("{0}|{1}", StationID, CanID),
SignalID = SignalIdMap[flag].SignalID,
Value = value * SignalIdMap[flag].Ratio,
StringValue = "",
DataStatus = 0,
UpdateTime = DateTime.Now
});
LogEvent.LogInfo.DebugFormat($"{Convert.ToString(flag, 16)}|{DataCopy.ToHexString(dataByteDic[flag])}|{value * SignalIdMap[flag].Ratio}");
}
//保存实时数据
RedisHelper redis = new RedisHelper((int)EnumUserRedisNum.RealData);
redis.ListRightPush(ConstValue.SetRealData, realList);
}
接收到实时数据解析处理就好了。
其他的一些数据类得定义:
namespace Protocol_Meter_DLT645_07
{
public class MessageInfo
{
#region 属性
/// <summary>
/// 帧起始符,68H
/// </summary>
public byte MessageHead { set; get; }
/// <summary>
/// 地址域,6字节
/// </summary>
public byte[] Addr { set; get; }
/// <summary>
/// 帧起始符,68H
/// </summary>
public byte StartHead { set; get; }
/// <summary>
/// 控制码
/// </summary>
public byte ControlCode { set; get; }
/// <summary>
/// 数据域长度
/// </summary>
public byte DataLength { set; get; }
/// <summary>
/// 数据标识
/// </summary>
public int DataFlag { set; get; }
/// <summary>
/// 数据域
/// </summary>
public byte[] Data { set; get; }
/// <summary>
/// 校验域
/// </summary>
public byte CheckSum { set; get; }
/// <summary>
/// 结束帧,16H
/// </summary>
public byte EndFrame { set; get; }
/// <summary>
/// 发送数据的SOCKET
/// </summary>
public string SessionID { set; get; }
/// <summary>
/// 原始包
/// </summary>
public byte[] MessageData { set; get; }
/// <summary>
/// 消息包是否有效
/// </summary>
public bool Valid { set; get; }
#endregion
#region 构造
public MessageInfo()
{
}
/// <summary>
/// 通过接收的数据构造函数
/// </summary>
/// <param name="message"></param>
public MessageInfo(ReviceMessage message)
{
try
{
MessageData = new byte[message.ReviceData.Length];
Buffer.BlockCopy(message.ReviceData, 0, MessageData, 0, message.ReviceData.Length);
int index = 0;
int dstOffset = 0;
// FE FE FE FE 68 22 52 88 00 00 00 68 91 07 33 33 37 35 33 33 33 CF 16
index += ConstValue.FE_Length;
// 帧起始符
MessageHead = DataCopy.GetByte(message.ReviceData, ref index);
// 地址域,6字节
Addr = new byte[6];
DataCopy.ByteCopy(message.ReviceData, index, Addr, ref dstOffset, message.ReviceData.Length, 6);
index += 6;
// 帧起始符
StartHead = DataCopy.GetByte(message.ReviceData, ref index);
// 控制码
ControlCode = DataCopy.GetByte(message.ReviceData, ref index);
// 数据域长度
DataLength = DataCopy.GetByte(message.ReviceData, ref index);
// 数据标识
DataFlag = DataCopy.GetINT(message.ReviceData, ref index);
// 数据域
int dataLength = message.ReviceData.Length - ConstValue.MessageLengthWithoutData - ConstValue.FE_Length + 4;
dstOffset = 0;
if (dataLength > 0)
{
Data = new byte[dataLength];
DataCopy.ByteCopy(message.ReviceData, index, Data, ref dstOffset, message.ReviceData.Length, dataLength);
index += dataLength;
}
// 校验码
CheckSum = DataCopy.GetByte(message.ReviceData, ref index);
// 结束符
EndFrame = DataCopy.GetByte(message.ReviceData, ref index);
SessionID = message.SessionID;
Valid = true;
}
catch (Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
Valid = false;
}
}
#endregion
#region 方法
/// <summary>
/// 将对象转化为二进制
/// </summary>
/// <returns></returns>
public byte[] ObjectToByte()
{
int messageLength = ConstValue.MessageLengthWithoutData;
if (Data != null)
messageLength += Data.Length;
int index = 0;
byte[] result = new byte[messageLength];
try
{
DataCopy.ByteCopy(ConstValue.FE_Head, 0, result, ref index, ConstValue.FE_Head.Length, messageLength);
// 包头
DataCopy.ByteCopy(MessageHead, result, ref index);
// 地址域
if (Addr != null)
DataCopy.ByteCopy(Addr, 0, result, ref index, Addr.Length, messageLength);
// 帧起始符
DataCopy.ByteCopy(StartHead, result, ref index);
// 控制码
DataCopy.ByteCopy(ControlCode, result, ref index);
// 数据域长度
DataCopy.ByteCopy(DataLength, result, ref index);
// 数据标识
DataCopy.ByteCopy(DataFlag, result, ref index);
// 消息包
if (Data != null)
DataCopy.ByteCopy(Data, 0, result, ref index, Data.Length, messageLength);
// 校验码
CheckSum = CheckSumHelp.AddCheckSum(result, 4, index);
DataCopy.ByteCopy(CheckSum, result, ref index);
// 数据标识
DataCopy.ByteCopy(EndFrame, result, ref index);
}
catch (Exception ex)
{
LogEvent.LogInfo.Fatal(ex.ToString());
return null;
}
return result;
}
#endregion
}
}
数据转换(十六进制和BCD的转换):
/// <summary>
/// BCD转16进制
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private byte HEX_to_BCD(byte data)
{
int temp;
temp = ((data >> 4) * 10 + (data & 0x0f));
return (byte)temp;
}
/// <summary>
/// 16进制转BCD
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private byte BCD_to_HEX(byte data)
{
int temp;
temp = (((data / 10) << 4) + (data % 10));
return (byte)temp;
}
校验和的处理:
namespace Protocol_Meter_DLT645_07
{
/// <summary>
/// 报文校验
/// </summary>
public class CheckSumHelp
{
/// <summary>
/// 校验和,左闭右开
/// </summary>
/// <param name="pchMsg"></param>
/// <param name="startByte"></param>
/// <param name="endByte"></param>
/// <returns></returns>
public static byte AddCheckSum(byte[] pchMsg, int startByte, int endByte)
{
try
{
int sum = 0;
for (int i = startByte; i < endByte; i++)
{
sum += pchMsg[i];
sum %= 256;
}
return (byte)sum;
}
catch(Exception ex)
{
LogEvent.Loger.Fatal(ex.ToString());
return 0;
}
}
}
}
解析完之后实时数据就可以做业务处理了,监控运行、历史数据统计等等...总的来说和97版本的协议差别不大。