• JT/T808协议 Delphi 实现


    JT/808协议全成是《JT/T808-2011道路运输车辆卫星定位系统终端通讯协议及数据格式》,是交通部2011年为GPS定位车载终端和监控平台之间的通信制定的规范。通信协议采用TCP或UDP,平台作为服务器端,终端作为客户端。

    unit JT808.Protocol;
    
    interface
    
      uses System.SysUtils;
    
    type
      TBCD6 = array [0 .. 5] of Byte;
    
      // 消息头
      TJT808Header = packed record // 12 bytes
        MsgId: Word;               // 消息ID
        Attr: Word;                // 属性
        Phone: TBCD6;              // 手机号
        MsgNum: Word;              // 流水号
      end;
    
      // 通用应答
      TCommonResponse = packed record // 19 bytes
        StartFlag: Byte;              //起始标志
        Header: TJT808Header;         //消息头
        MsgNum: Word;                 //消息流水号
        MsgId: Word;                  //消息Id
        &Result: Byte;                //结果,0=成功/确认, 1=失败, 2=消息有误,3=不支持, 4=报警消息确认
        EndFlag: Byte;                //结束标志
      end;
    
      // 设备注册消息体
      TDeviceRegisterBody = packed record     // 33 bytes
        ProvinceID: Word;                     // 省域ID
        CityID: Word;                         // 市域ID
        VendorId: array [0 .. 4] of Byte;     // 制造商ID
        DeviceModel: array [0 .. 19] of Byte; // 设备型号
        DeviceId: array [0 .. 6] of Byte;     // 设备ID
        PlateColor: Byte;                     // 车牌颜色
        PlateNo: array [0 .. 7] of Byte;      // 车牌号码
      end;
    
      // 设备注册消息
      TDeviceRegisterMsg = packed record
        StartFlag: Byte;
        Header: TJT808Header;
        Body: TDeviceRegisterBody;
        CheckSum: Byte;
        EndFlag: Byte;
      end;
    
      // 设备注册应答
      TRegisterResponse = packed record
        StartFlag: Byte;
        Header: TJT808Header;
        MsgNum: Word;
        &Result: Byte;
      end;
    
      // 位置信息消息体
      TGPSLocationBody = packed record
        Alarm: LongWord;           //报警标志位
        Status: LongWord;          //状态位
        Lat: LongWord;             //以度为单位的纬度值乘以10的6次方,精确到百万分之一度
        lng: LongWord;             //以度为单位的经度值乘以10的6次方,精确到百万分之一度
        Altitude: Word;            //海拔高度,米
        Speed: Word;               //车速1/10km/h
        Angle: Word;               //方向0~359
        Time: TBCD6;               //时间
      end;
    
      // 位置信息
      TGPSLocationMsg = packed record
        StartFlag: Byte;
        Header: TJT808Header;
        Body: TGPSLocationBody;
        CheckSum: Byte;
        EndFlag: Byte;
      end;
    
      // 心跳消息,消息体为空
      TKeepLiveMsg = packed record
        StartFlag: Byte;
        Header: TJT808Header;
        CheckSum: Byte;
        EndFlag: Byte;
      end;
    
    const
      JT808_DATA_FLAG: Word            = $7E;   // 消息头尾标记
      JT808_ID_DEVICE_RESP: Word       = $0001; // 终端普通应答
      JT808_ID_SERVER_COMMONRESP: Word = $8001; // 平台普通应答
      JT808_ID_SERVER_RESP: Word       = $8100; // 平台对终端注册应答
      JT808_ID_DEVICE_KEEP_LIVE: Word  = $0002; // 终端心跳
      JT808_ID_DEVICE_REG: Word        = $0100; // 终端注册
      JT808_ID_DEVICE_LOGOUT: Word     = $0003; // 终端注销
      JT808_ID_DEVICE_AUTH: Word       = $0102; // 终端鉴权
      JT808_ID_DEVICE_LOCATION: Word   = $0200; // 位置信息
    
      SERVER_RESP_RESULTS: array [0 .. 4] of string = ('成功/确认', '失败', '消息有误', '不支持', '报警消息确认');
    
      //返回新的消息流水号
      function NewMsgNum: Word;
      function StrColorToInt(const Value: string): Integer;
    
      /// <summary>
      /// 校验码,从消息头开始,同后一字节异或,直到校验码前一字节。
      /// </summary>
      /// <param name="Buff">校验的数据</param>
      /// <param name="Count">数据长度</param>
      /// <param name="Offset">偏移量</param>
      /// <returns>校验码</returns>
      function GetCheckSum(Buff: TBytes; Count: Integer; const Offset: Integer = 0): Byte;
    
      /// <summary>
      /// 纬度转换为整型
      /// </summary>
      /// <param name="Value">经度</param>
      /// <returns>经度乘以10的6次方</returns>
      function LatLngToInt(Value: Double): LongWord;
    
      /// <summary>
      /// 经度转换为整型
      /// </summary>
      /// <param name="Value">经度</param>
      /// <returns>经度乘以10的6次方</returns>
      function IntToLatlng(Value: LongWord): Double;
    
      function StrToBcd6(Value: string): TBCD6;
      /// <summary>
      /// 字节转义,因为数据头尾标识位是7E,其他地方出现则需要转义。
      /// </summary>
      /// <param name="Source">要转义的内容</param>
      /// <param name="Count">转义内容长度</param>
      /// <param name="Dest">转义后内容</param>
      /// <returns>转义后长度</returns>
      function JT808Encode(Source: TBytes; Count: Integer; var Dest:TBytes):Integer;
      function JT808Decode(Source: TBytes; Count: Integer; var Dest:TBytes): Integer;
    
    implementation
    
    var
      __MsgNum: Word = $100A;
    
    function NewMsgNum: Word;
    begin
      Result := __MsgNum;
      Inc(__MsgNum);
    end;
    
    function StrColorToInt(const Value: string): Integer;
    const
      Colors: array[1..5] of string = ('蓝色', '黄色', '黑色', '白色', '红色');
    begin
      for var I := 1 to High(Colors) do
        if Colors[I] = Value then
          Exit(I);
    
      Exit(0);
    end;
    function GetCheckSum(Buff: TBytes; Count: Integer; const Offset: Integer): Byte;
    var
      I: Integer;
    begin
      Result := Buff[Offset];
      for I := Offset to Count - Offset - 1 do
        Result := Result xor Buff[I];
    end;
    
    
    function LatLngToInt(Value: Double): LongWord;
    begin
      Result := Trunc(Value * 1000000);
    end;
    
    function IntToLatlng(Value: LongWord): Double;
    begin
      Result := Value / 1000000;
    end;
    
    function StrToBcd6(Value: string): TBCD6;
      function Encode(Left, Right: Char): Byte;
      begin
        Result := StrToInt(Left) shl 4 or StrToInt(Right);
      end;
    var
      I, J: Integer;
    begin
      FillChar(Result[0], SizeOf(TBCD6), 0);
      //补足12位
      Value := Value.PadLeft(12,'0');
    
      J := 0;
      I := 0;
      while I < Value.Length - 1 do
      begin
        Result[J] := Encode(Value.Chars[I], Value.Chars[I + 1]);
        Inc(J);
        Inc(I, 2);
      end;
    end;
    
    function JT808Encode(Source: TBytes; Count: Integer;var Dest:TBytes):Integer;
    var
      B: Byte;
      I,J: Integer;
    begin
      J :=  0;
      I := 0;
    
      SetLength(Dest,Count*2);
    
      Dest[J] := Source[I];
      Inc(J);
      for I := 1 to Count - 2 do
      begin
        B := Source[I];
        if B = $7E then
        begin
          Dest[J] := $7D;
          Inc(J);
          Dest[J] := $02;
        end
        else if B = $7D then
        begin
          Dest[J] := $7D;
          Inc(J);
          Dest[J] := $01;
        end
        else
        begin
          Dest[J] := Source[I];
        end;
        Inc(J);
      end;
      Dest[J] := Source[Count - 1];
      Inc(J);
    
      SetLength(Dest,J);
      Result := J;
    end;
    
    function JT808Decode(Source: TBytes; Count: Integer; var Dest:TBytes): Integer;
    var
      I,J: Integer;
      B, C: Byte;
    begin
      Result:=0;
      if (Count <= 0) or (Count > 2048) then
        Exit;
    
      SetLength(Dest,Count);
    
      I := 0;
      J := 0;
      while (I <= Count - 2) do
      begin
        B := Source[I];
        C := Source[I + 1];
        if (B = $7D) and (C = $02) then
        begin
          Dest[J] := $7E;
          Inc(I, 2);
        end
        else if (B = $7D) and (C = $01) then
        begin
          Dest[J] := $7D;
          Inc(I, 2);
        end
        else
        begin
          Dest[J] := Source[I];
          Inc(I, 1);
        end;
        Inc(J);
      end;
      if I < Count then
      begin
        Dest[J] := Source[I];
        Inc(J);
      end;
      SetLength(Dest,J);
      Result:=J;
    end;
    
    end.
  • 相关阅读:
    平衡二叉树
    2020年度总结
    go中string是如何实现的呢
    escape的编码解码
    小程序实现下载图片到手机及文字到手机粘贴板
    小程序分享(单页面,朋友圈)
    sql server单行拆分成多行
    sql server 查询分组后用逗号拼接字符串和拆分
    安装虚拟机
    Lombok插件安装
  • 原文地址:https://www.cnblogs.com/rtcmw/p/12760152.html
Copyright © 2020-2023  润新知