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.