NMEA

NMEA is the communication standard used with GPS devices. A websearch for 'NMEA'
will find the complete protocol. Here only a part of it is implemented. Though
this application uses a realtime kernel, just a serial receiver will do.

program Graminreceiver;

uses opstring,opcrt,RTKERNEL,NMEA;

var s:string;
i:integer;

begin
 signal(nmeastart);
 repeat
  rtkernel.delay(50);
  s:=NMEAStrings.rec+' '+NMEAStrings.time+' '+NMEAStrings.date+' '+
     NMEAStrings.latitude+' '+NMEAStrings.longitude+' '+
     NMEAStrings.speed+' '+NMEAStrings.magnetic;
  wait(screensema);
  writeln(s);
  writeln(NMEAData.latitude,' ',NMEAData.longitude);
  signal(screensema);
 until keypressed;
 i:=0;
end.
and the NMEA unit :
unit nmea;

interface

uses RTKernel,RTCom;

type
 NMEAstr=record
  time:string[10];
  date:string[10];
  latitude:string[10];
  longitude:string[10];
  speed:string[10];
  magnetic:string[10];
  madegood:string[10];
  rec:string[10];
  fixq:char;
  satcnt:char;
  hdil:string[10];
  altitude:string[10];
  geodelta:string[10];
  hpe,vpe,spe:string[10];
 end;
 NMEARData=record
  latitude,
  longitude,speed:extended;
 end;


var nmeastart:RTKERNEL.Semaphore;
    nmeaaccess:RTKernel.Semaphore;
    nmeadtaskhandle:RTKERNEL.Taskhandle;
    NMEAStrings:NMEAStr;
    NMEAData:NMEARData;
    rs:string;
    ScreenSema:RTKernel.Semaphore;

implementation

const NMEAPort=COM2;

procedure initnmea;
begin
 if RTCOM.portinstalled(NMEAPort) then
  begin
   RTCOM.InitPort(NMEAPort,4800,none,1,8);
   RTCOM.EnableCOMInterrupt(NMEAPort,1000);
  end;
 NMEAStrings.rec:='no msg  ';
end;

{$F+}
procedure nmeatask;
var currentstr,s:string;
    data:RTCOM.V24Data;
    strcomplete,next,success:boolean;
    index:byte;
    deg:integer;
    min:single;

 function nextcomma(s:string;var index:byte;var sub:string):boolean;
 var j:byte;
 begin
  j:=index;sub:='';
  while(s[j]<>',')and(s[j]<>'*')do begin
   sub:=sub+s[j]; inc(j);
  end;
  nextcomma:=(index=j);
  index:=j+1;
 end;

begin
 ProtectCoprocessor(TRUE);
 initnmea;
 wait(nmeastart);
 currentstr:='';
 while true do
  begin
   strcomplete:=false;currentstr:='';
   repeat
    RTCOM.GetTimed(RTCOM.ReceiveBuffer[NMEAPort],data,90,success);
    if (not success) then NMEAStrings.rec:='no msg  '
    else
     begin
      strcomplete:=(data.ch=chr(10)); { linefeed }
      {strcomplete:=(length(currentstr)>200);}
      currentstr:=currentstr+data.ch;
     end;
   until strcomplete;
   rs:=currentstr;
{   wait(screensema);
   writeln(rs);
   signal(screensema);}
   s:=copy(currentstr,1,6); next:=false;
   if (s='$GPRMC') then
    begin
{     wait(screensema); writeln(currentstr); signal(screensema);}
     index:=8;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.time:=s;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       if s='A'then NMEAStrings.rec:='ok      ';
       if s='V'then NMEAStrings.rec:='warning ';
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.latitude:=s;
       deg:=10*(ord(s[1])-$30)+(ord(s[2])-$30);
       min:=10*(ord(s[3])-$30)+(ord(s[4])-$30)
	  +0.1*(ord(s[6])-$30)+0.01*(ord(s[7])-$30)
	  +0.001*(ord(s[8])-$30);
       NMEAData.latitude:=pi*(deg+(min/60))/180.0;
       if not nextcomma(currentstr,index,s) then
	begin
	 NMEAStrings.latitude:=NMEAStrings.latitude+s;
	 if s='S' then NMEAData.latitude:=-NMEAData.latitude;
	end;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.longitude:=s;
       deg:=100*(ord(s[1])-$30)+10*(ord(s[2])-$30)+(ord(s[3])-$30);
       min:=10*(ord(s[4])-$30)+(ord(s[5])-$30)+0.1*(ord(s[7])-$30)
	  +0.01*(ord(s[8])-$30)+0.001*(ord(s[9])-$30);
       NMEAData.longitude:=pi*(deg+(min/60))/180.0;
       if not nextcomma(currentstr,index,s) then
	begin
	 NMEAStrings.longitude:=NMEAStrings.longitude+s;
	 if s='W' then NMEAData.longitude:=-NMEAData.longitude;
	end;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.speed:=s;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.madegood:=s;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.date:=s;
      end;
     if not nextcomma(currentstr,index,s) then
      begin
       NMEAStrings.magnetic:=s;
       if not nextcomma(currentstr,index,s) then
	NMEAStrings.magnetic:=NMEAStrings.magnetic+s;
      end;
     next:=true;
    end;
   if (not next)and(s='$GPRMB') then
    begin

     next:=true;
    end;
   if (not next)and(s='$GPGGA') then
    begin

     next:=true;
    end;
   if (not next)and(s='$GPGSA') then
    begin

     next:=true;
    end;
   if (not next)and(s='$GPGSV') then
    begin

     next:=true;
    end;
   if (not next)and(s='$PGRME') then
    begin

     next:=true;
    end;
   if (not next)and(s='$GPGLL') then
    begin

     next:=true;
    end;
   if (not next)and(s='$PGRMZ') then
    begin

     next:=true;
    end;
   if (not next)and(s='$PGRMM') then
    begin

     next:=true;
    end;
   if (not next)and(s='$GPBOD') then
    begin

     next:=true;
    end;
  end; { while true loop }
end; {nmeatask}

begin
 initsemaphore(nmeastart,binary,0,'nmeastart');
 initsemaphore(nmeaaccess,resource,1,'nmeaaccess');
 initsemaphore(ScreenSema,resource,1,'screensema');
 createtask(nmeatask,mainpriority-1,2000,'NMEA',nmeadtaskhandle);
{ signal(screensema);}
end.


home

last updated: 26.jan.00

Copyright (99,2000) Ing.Büro R.Tschaggelar