Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for Robust Delphi NMEA parser

I'm looking for opensource Delphi NMEA parser of production grade.

It will be fine if it can meet critical mission requirement (I'm joking! I believe it's not attainable using a Win32 system).

So far, I have played around with basic interfacing of a wrist GPS (Garmin Foretrex 101) through serial port using basic windows API (NMEA 0183).

I have also explored an opensource VCL component to handle experimental serial communication with an aviation model GPS (Garmin Gpsmap 196).

Thanks.

like image 843
menjaraz Avatar asked Oct 10 '22 05:10

menjaraz


1 Answers

I end up using TComPort and TComDataPacket from the open source TComPort package.


ComPort setting:

  object ComPort: TComPort
    BaudRate = br4800
    Port = 'COM1'
    Parity.Bits = prNone
    StopBits = sbTwoStopBits
    DataBits = dbEight
    Events = [evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR, evError, evRLSD, evRx80Full]
    FlowControl.OutCTSFlow = False
    FlowControl.OutDSRFlow = False
    FlowControl.ControlDTR = dtrDisable
    FlowControl.ControlRTS = rtsDisable
    FlowControl.XonXoffOut = False
    FlowControl.XonXoffIn = False
    SyncMethod = smWindowSync
    OnAfterOpen = ComPortAfterOpen
    OnAfterClose = ComPortAfterClose
    Left = 904
    Top = 192
  end

ComDataPacket settings:

  object ComDataPacket: TComDataPacket
    ComPort = ComPort
    StartString = '$'
    StopString = '*'
    OnPacket = ComDataPacketPacket
    Left = 808
    Top = 240
  end

Excerpt of type used

type
  // NMEA 0185's messages used
  TMsgGP = (
    msgGP,    // Unknown message
    msgGPGGA, // Global Positioning System Fix Data
    msgGPGLL, // Geographic position, Latitude and Longitude
    msgGPGSV, // Satellites in view
    msgGPRMA, // Recommended minimum specific GPS/Transit data Loran C
    msgGPRMC, // Recommended minimum specific GPS/Transit data
    msgGPZDA  // Date and time
    );

  // Satellite properties
  TSatellite = record
    Identification: ShortInt;
    Elevation: 0..90;
    Azimut: Smallint;
    SignLevel: Smallint;
  end;
  // Array of satellites referenced
  TSatellites = array[1..MAX_SATS] of TSatellite;

  // GPS status informations
  TGPSDatas = record
    Latitude: Double;
    Longitude: Double;
    HeightAboveSea: Double;
    Speed: Double;
    UTCTime: TDateTime;
    Valid: Boolean;
    NbrSats: Shortint;
    NbrSatsUsed: Shortint;
  end;

ComDataPacketPacket Event handler:

procedure TForm1.ComDataPacketPacket(Sender: TObject; const Str: string);
var
  Resultat: TStringList;
  MsgCorrect, TypeMsg: string;
  i: Integer;
begin
  Resultat := TStringList.Create;
  try

    // Split the message into different parts.
    MsgCorrect := AnsiReplaceStr('$'+Str, ',,', ' , , ');
    Resultat.Text := AnsiReplaceStr(LeftStr(MsgCorrect, Length(MsgCorrect) - 1), ',', #13#10);

    // Get the message type
    TypeMsg := AnsiMidStr(Resultat[0], 4, 3);

    case IndexMsgGP(TypeMsg) of
      msgGPGGA:
        begin
        end;
      msgGPGLL:
        begin
        end;
      msgGPGSV:
        begin
          // If there are satellites referenced in the frame
          if Resultat.Count < 4 then
            FGPSDatas.NbrSats := 0
          else
            FGPSDatas.NbrSats := StrToInteger(Resultat[3]);

          if Resultat[2] = '1' then
          begin
            FSatRef := 0;

            // Initiate satellites values
            for i := 1 to 12 do
              with FSatellites[i] do
              begin
                Identification := 0;
                Elevation := 0;
                Azimut := 0;
                SignLevel := 0;
              end;
          end;

          i := 4;

          // For each referenced satellites
          while (i + 4) <= (Resultat.Count) do
          begin
            with FSatellites[FSatRef + 1] do
            begin
              Identification := StrToInteger(Resultat[i]);
              Elevation := StrToInteger(Resultat[i + 1]);
              Azimut := StrToInteger(Resultat[i + 2]);
              if Resultat[i + 3] <> '' then
                SignLevel := StrToInteger(Resultat[i + 3])
              else
                SignLevel := 0;
            end;
            Inc(i, 4);
            Inc(FSatRef);
          end;
        end;
      msgGPRMA:
        begin
        end;
      msgGPRMC:
        begin
        end;
      msgGPZDA:
        begin
        end;
      else
    end;
  finally
    Resultat.Free;
  end;
end;

NMEA processing took place in the event handler.

like image 97
menjaraz Avatar answered Oct 13 '22 10:10

menjaraz