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' );
View Code

   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; }
View Code

  初始化请求包:

        /// <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);
                }
            }
        }
View Code

  初始化解析数据包:

       /// <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);
            }
        }
View Code

  初始化电表地址等:

        /// <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());
            }
        }
View Code

  两个线程一发一收,我们这里用到了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());
            }
        }
View Code

  接收实时数据应答线程:

        /// <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);
        }
View Code

  接收到实时数据解析处理就好了。

  其他的一些数据类得定义:

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

    }
}
View Code

  数据转换(十六进制和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;
        }
View Code

  校验和的处理:

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;
            }
        }
    }
}
View Code

  解析完之后实时数据就可以做业务处理了,监控运行、历史数据统计等等...总的来说和97版本的协议差别不大。

posted @ 2020-12-13 12:23  7嗨嗨  阅读(2789)  评论(17编辑  收藏  举报