当前位置: 移动技术网 > IT编程>开发语言>.net > 北斗数据包格式封装和解析

北斗数据包格式封装和解析

2019年03月12日  | 移动技术网IT编程  | 我要评论

网络图怎么画,草图大师教程,什么牌子电动车最好

1.北斗协议的具体格式如下图

image.png

image.png

2.数据包类型 根据北斗协议类型定义如下枚举类型

 /// <summary>
    /// 数据包类型
    /// </summary>
    public enum bdframetype : ushort
    {
        /// <summary>
        /// 默认
        /// </summary>
        default = 0x00,
 
        /// <summary>
        /// 终端通用应答
        /// </summary>
        tercommonresponse = 0x0001,
 
        /// <summary>
        /// 平台通用应答
        /// </summary>
        platcommonresponse = 0x8001,
 
        /// <summary>
        /// 终端心跳
        /// </summary>
        terheartbeat = 0x0002,
         
         
             /// <summary>
             /// 位置信息汇报
            /// </summary>
              position = 0x0200
         
        //省略其他的数据包类型
 
    }

3.基础类封装 bdbaseframe,使用 ibytebuffer 类来封装数据包,ibytebuffer 内置提供了很多字节操作方法(read,write) 

bytebuffer.readunsignedshort()
bytebuffer.writeunsignedshort()
//等等
public abstract class bdbaseframe
    {
        /// <summary>
        /// 消息id
        /// </summary>
        public bdframetype frametype { get; set; }
 
        /// <summary>
        /// 是否分包
        /// </summary>
        public bool issubpackage { get; set; }
 
        /// <summary>
        /// 加密方式
        /// </summary>
        public bdframeencrypttype frameencrypttype { get; set; }
 
        /// <summary>
        /// 消息体长度
        /// </summary>
        public uint16 framecontentlen { get; private set; }
 
        /// <summary>
        /// 终端手机号  唯一
        /// </summary>
        public string terminalphone { get; set; } = string.empty;
 
 
        /// <summary>
        /// 消息流水号
        /// </summary>
        public ushort frameserialnum { get; set; }
 
        /// <summary>
        /// 消息总包数
        /// </summary>
        public ushort framepackagecount { get; set; }
 
        /// <summary>
        /// 包序号  从 1开始
        /// </summary>
        public ushort framepackageindex { get; set; }
 
 
        private int m_framebodyoffset = 13;
 
        /// <summary>
        /// 消息体 数据偏于量
        /// </summary>
        protected int framebodyoffset
        {
            get { return m_framebodyoffset; }
        }
 
        private static ushort m_sendframeserialnum = 0;
 
        /// <summary>
        /// 获取发送的流水号
        /// </summary>
        public static ushort sendframeserialnum
        {
            get
            {
                if (m_sendframeserialnum == ushort.maxvalue)
                    m_sendframeserialnum = 0;
 
                m_sendframeserialnum++;
 
                return m_sendframeserialnum;
            }
        }
 
        /// <summary>
        /// 数据包内容 字节
        /// </summary>
        //public ibytebuffer contentbuffer { get; set; }
 
        #region 解析数据包
        /// <summary>
        /// 解析头部
        /// </summary>
        private void decoderhead(ibytebuffer bytebuffer)
        {
            //消息体属性
            bytebuffer.setreaderindex(1);
            frametype = (bdframetype)bytebuffer.readunsignedshort();
            ushort frameproerty = bytebuffer.readunsignedshort();
            issubpackage = framehelper.readboolean16(frameproerty, 13);
            framecontentlen = (uint16)(frameproerty & 0x1fff);//消息体长度
            if (issubpackage)
                m_framebodyoffset = 17;
            //终端手机号
            stringbuilder stringbuilder = new stringbuilder();
            for (int i = 0; i < 6; i++)
            {
                stringbuilder.append(bytebuffer.readbyte().tostring("x2"));
            }
            terminalphone = stringbuilder.tostring().trimstart(new char[] { '0' });
            //消息流水号
            frameserialnum = bytebuffer.readunsignedshort();
            //消息包封装项
            if (issubpackage)
            {
                framepackagecount = bytebuffer.readunsignedshort();
                framepackageindex = bytebuffer.readunsignedshort();
            }
        }
 
        /// <summary>
        /// 解析内容
        /// </summary>
        public virtual void decoderframe(ibytebuffer bytebuffer)
        {
            //解析头部
            decoderhead(bytebuffer);
        }
 
        #endregion
 
        #region 封装数据包
 
        public virtual ibytebuffer encodercontent()
        {
            return null;
        }
 
        #endregion
 
        public override string tostring()
        {
            return $"{terminalphone} {frametypehelper.getframetype(frametype)}  {datetime.now.tostring("yyyy-mm-dd hh:mm:ss")}";
        }
    }

4.具体数据包类型封装 positionframe

 /// <summary>
    /// 位置信息汇报
    /// </summary>
    public class positionframe : bdbaseframe
    {
        public positionframe()
        {
            frametype = bdframetype.position;
        }
 
        /// <summary>
        /// 报警标志
        /// </summary>
        public uint32 alarmflag { get; set; }
 
        /// <summary>
        /// 状态
        /// </summary>
        public uint32 statusflag { get; set; }
 
        /// <summary>
        /// 纬度 dword 以度为单位的纬度值乘以 10 的 6 次方,精确到百万分之一度
        /// </summary>
        public double lat { get; set; }
 
        /// <summary>
        /// 经度 dword 以度为单位的经度值乘以 10 的 6 次方,精确到百万分之一度
        /// </summary>
        public double lng { get; set; }
 
        /// <summary>
        /// 高程 word 海拔高度,单位为米(m)
        /// </summary>
        public uint16 height { get; set; }
 
        /// <summary>
        /// 速度 word 1/10km/h
        /// </summary>
        public float speed { get; set; }
 
        /// <summary>
        /// 方向 word 0-359,正北为 0,顺时针
        /// </summary>
        public uint16 direction { get; set; }
 
        /// <summary>
        /// 时间 bcd[6] yy-mm-dd-hh-mm-ss(gmt+8 时间,本标准中之后涉及的时间均采用此时区)
        /// </summary>
        public datetime gpsdatetime { get; set; }
 
        public override void decoderframe(ibytebuffer bytebuffer)
        {
            base.decoderframe(bytebuffer);
 
            alarmflag = bytebuffer.readunsignedint();
            statusflag = bytebuffer.readunsignedint();
            lat = bytebuffer.readunsignedint() / 1000000.0;
            lng = bytebuffer.readunsignedint() / 1000000.0;
            height = bytebuffer.readunsignedshort();
            speed = bytebuffer.readunsignedshort() / 10.0f;
            direction = bytebuffer.readunsignedshort();
            //时间 bcd[6]
            byte[] bcdtime = new byte[6];
            bytebuffer.readbytes(bcdtime);
            string bcdtimestring = framehelper.bcd2string(bcdtime);
            datetime gpstime;
            if (datetime.tryparseexact(bcdtimestring, "yymmddhhmmss", new cultureinfo("zh-cn", true), datetimestyles.none, out gpstime))
                gpsdatetime = gpstime;
            else
                gpsdatetime = new datetime(2001, 1, 1, 0, 0, 0);
        }
 
 
        public override ibytebuffer encodercontent()
        {
            ibytebuffer contentbuffer = unpooled.buffer(100, 1024);
            contentbuffer.writeint((int)alarmflag);
            contentbuffer.writeint((int)statusflag);
            contentbuffer.writeint((int)(lat * 1000000));
            contentbuffer.writeint((int)(lng * 1000000));
            contentbuffer.writeunsignedshort(height);
            contentbuffer.writeunsignedshort((uint16)(speed * 10));
            contentbuffer.writeunsignedshort(direction);
            //时间 bcd[6]
            byte[] timebcdbuffer = framehelper.writebcdstring(gpsdatetime.tostring("yymmddhhmmss"));
            contentbuffer.writebytes(timebcdbuffer);
            return contentbuffer;
        }
 
        public override string tostring()
        {
            return string.format("通讯号:{0},时间:{1},经纬度{2}|{3},高度:{4},方向:{5}", terminalphone, gpsdatetime.tostring("yyyy-mm-dd hh:mm:ss"), lng, lat, height, direction);
        }
    }

5.dotnetty encoderhandler 封装,上面封装的只是消息体的数据,没有包括标识位,消息头,验证码,标识位,在发送数据通道中,需要把数据加上标识位,消息头,验证码,标识位。包括数据包转义

 /// <summary>
    /// 北斗数据包 封装
    /// </summary>
    public class beidoucontentencoderhandler : messagetobyteencoder<bdbaseframe>
    {
        protected override void encode(ichannelhandlercontext context, bdbaseframe message, ibytebuffer output)
        {
            encodeframe(message, output);
        }
 
        private void encodeframe(bdbaseframe message, ibytebuffer output)
        {
            //ibytebuffer framebuffer = output;
            output.markreaderindex();
            //内容
            ibytebuffer contentbuffer = message.encodercontent();
            if (contentbuffer == null)
                contentbuffer = unpooled.empty;
            //byte[] content = new byte[contentbuffer.readablebytes];
            //contentbuffer.readbytes(content, 0, content.length);
            //写头标志
            output.writebyte(bdframeconst.frame_flag);
            //消息 id
            output.writeunsignedshort((ushort)message.frametype);
            //消息体属性  加密没做
            // ushort contentlen = (ushort)content.length;
            ushort contentlen = (ushort)contentbuffer.readablebytes;
            if (message.issubpackage)
            {
                contentlen = (ushort)(contentlen | 0x2000);
                output.writeunsignedshort(contentlen);
            }
            else
            {
                output.writeunsignedshort(contentlen);
            }
            //终端手机号
            string tphone = message.terminalphone.tostringframepropertylength(12, '0');
            byte[] tphonebuffer = czeframehelper.writebcdstring(tphone);
            output.writebytes(tphonebuffer);
            //消息流水号
            output.writeunsignedshort(message.frameserialnum);
            //消息包封装项
            if (message.issubpackage)
            {
                output.writeunsignedshort(message.framepackagecount);
                output.writeunsignedshort(message.framepackageindex);
            }
            //消息体
            output.writebytes(contentbuffer);
            contentbuffer.release();
            //计算校验码
            byte[] checkcodebuffer = new byte[output.readablebytes];
            output.readbytes(checkcodebuffer, 0, checkcodebuffer.length);
            byte value = checkcodebuffer[1];
            for (int i = 2; i < checkcodebuffer.length; i++)
                value ^= checkcodebuffer[i];
            output.writebyte(value);
            //写尾标志
            output.writebyte(bdframeconst.frame_flag);
            //转义
            output.resetreaderindex();
            checkcodebuffer = new byte[output.readablebytes];
            output.readbytes(checkcodebuffer, 0, checkcodebuffer.length);
            byte[] frame = frameescaping.bdescapingbuffersend(checkcodebuffer);
 
            //数据写入 framebuffer
            output.clear();
            output.writebytes(frame);
        }
 
    }

6.使用 beidoucontentencoderhandler,在通道中加入beidoucontentencoderhandler,通道里面的顺序很重要,beidoucontentencoderhandler必须要在你发送的handler前加到通道中去如下图

 

主要的代码就这些,水平有限,请大家多多指教

原文地址 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网