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.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM