unit uNMEA;
// Helpful NMEA tools.

interface
  uses Classes;

  type
    tStrArray = array of string;

function NMEA_SetChecksum( SIN: string; var CS: byte ): string;
function  NMEA_TestChecksum( S: string; var CS: byte ): boolean;
function  NMEA_Parse( S: string;
                      var tokens: tStrArray ): cardinal;

implementation

uses uComUtil, SysUtils, uUtility;

function NMEA_SetChecksum( SIN: string; var CS: byte ): string;
var
  i: cardinal;                          // index
  S: string;
begin
  {$R-}                                 // range checking off for Checksum calculation
  // Check for proper checksum if checksum is enabled.
  // Compute the Actual Checksum
  S  := SIN;
  CS := 0;                              // init checksum
  for i:=1 to Length(S) do
  begin
    cs := cs XOR Ord(S[i]);
  end;
  {$R+}
  S := '$'+S+'*'+St_HB(cs)+^M^J;
  result := s;
end;

function  NMEA_TestChecksum( S: string; var CS: byte ): boolean;
var
  i: cardinal;                          // index
  Astrick: cardinal;                    // location of * in stripped message
  acs: byte;
begin
  result := FALSE;                      // assume failure
  // Strip Out the NMEA message
  //i := Pos( '$', S );
  //if i=0 then exit;                     // no NMEA message in this string
  //Delete( S, 1, i-1 );                  // prequalified NMEA string
  if Length(S) < 2 then exit;           // bail if message is too short
  Astrick := Pos( '*', S );             // where is the *
  if Astrick<1 then
  begin
    result := FALSE;
    exit;
  end;
  {$R-}                                 // range checking off for Checksum calculation
  // Check for proper checksum if checksum is enabled.
  // Get the Alledged Checksum
  acs := HexCharPairToByte( S[Astrick+1] + S[Astrick+2] );
  // Compute the Actual Checksum
  CS := 0;                              // init checksum
  for i:=2 to Astrick-1 do
  begin
    cs := cs XOR Ord(S[i]);
  end;
  // Correct checksum?
  if CS <> ACS then exit;               // Bad Checksum?
  // NAK
  if FirstChar( S )=^U then exit;       // Receiver NAK
  result := TRUE;
end;

function NMEA_Parse( S: string;
                      var tokens: tStrArray ): cardinal;
var
  Preamble: string;
  i: cardinal;
  H: integer;
begin
  result := 0;
  SetLength( tokens, 0 );
  // Strip Out the NMEA message
  i := Pos( '$', S );
  if i=0 then exit;                     // no NMEA message in this string
  Preamble := Copy( S, 1, i );        // save any preamble
  Delete( S, 1, i );                  // prequalified NMEA string
  // Strip Out from Asterick on
  i := Pos( '*', S );
  Delete( S, i, Length(S)-i+1 );
  if Length(S) < 2 then exit;           // bail if message is too short
  // Comma parse the NMEA input string
  while (Length(S)>0) do
  begin
    SetLength( tokens, High(Tokens)+2 );
    result := High(tokens);
    tokens[result] := Trim(CommaParse(S));
  end;
  result := High(Tokens)+1;
end;

end.
