码迷,mamicode.com
首页 > Windows程序 > 详细

C#-DL/T 645—2007协议

时间:2020-12-18 12:34:09      阅读:4      评论:0      收藏:0      [点我收藏+]

标签:gif   sum   prot   Nid   fse   log   scl   pac   push   

  前面一篇写了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版本的协议差别不大。

C#-DL/T 645—2007协议

标签:gif   sum   prot   Nid   fse   log   scl   pac   push   

原文地址:https://www.cnblogs.com/7haihai/p/14032374.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!