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.