data @0, "GPS parser BDT 30 May 2006 " '**************************************************************** '* Name : GPSparser05.PBP * '* Author : Brian Taylor * '* Notice : Copyright (c) 2006 Brian Taylor * '* : All Rights Reserved * '* Date : 30 MAY 2006 * '* Version : 0.05 * '* Notes : * '* : * '**************************************************************** ' a. Uses a single 84 character array. ' b. Gets RMB on one pass and RMC on the next pass so has slowish updates ' c. Code extracts every field of RMB and some fields of RMC ' d. There is no Checksum validation used. DEFINE OSC 20 DEFINE loader_used 1 DEFINE CHAR_PACING 1000 'add a few extra stop bits to each character ' Set LCD Data port DEFINE LCD_DREG PORTD ' Set starting Data bit (0 or 4) if 4-bit bus DEFINE LCD_DBIT 0 ' Set LCD Register Select port DEFINE LCD_RSREG PORTD ' Set LCD Register Select bit DEFINE LCD_RSBIT 5 ' Set LCD Enable port DEFINE LCD_EREG PORTD ' Set LCD Enable bit DEFINE LCD_EBIT 4 ' Set LCD bus size (4 or 8 bits) DEFINE LCD_BITS 4 ' Set number of lines on LCD DEFINE LCD_LINES 2 ' Set command delay time in us DEFINE LCD_COMMANDUS 2000 ' Set data delay time in us DEFINE LCD_DATAUS 500 @ Device pic16F877, HS_OSC, BOD_OFF, PWRT_ON, WDT_ON, PROTECT_OFF '@__config_HS_OSC &_BOD_OFF &_PWRT_ON &_WDT_ON &_PROTECT_OFF &_LVP_OFF trisa = %11111111 trisb = %11111111 trisc = %10011111 trisd = %00000000 trise = %00000000 OPTION_REG = %10001111 ' no pullups, prescaler to WDT /128 '************************** Hardware definition *************************** 'Uses generic Olimex P40 board. DiagLED var porta.0 ' Olimex standard LED GoLED var portc.5 ' pin 24 on '877 BootOut var portc.6 ' Bootloader Output BootIn var portc.7 ' Bootloader Input Tx232 var portd.6 ' SEROUT to GPS Rx232 var portd.7 ' SERIN from GPS 'LCD is on port D '************************* Software variables **************************** A var byte[84] B var byte C var byte D var byte E var byte F var byte I var byte J var byte V var word Track var word 'track x 10 in degrees True XTE var word 'cross track error x 10 in Kms Bearing var word 'bearing to destination x 10 True 'CheckSum var byte CommaCnt var byte lcdout $FE, $01 'initialise display goto startup 'jump Subroutines at startup ' *************************** SubRoutines ***************************** ' ************************* Initialise ******************************** Startup: Initialise: OPTION_REG = %00001111 ' no pullups, prescaler to WDT /128 INTCON = %00000000 PIE1 = %00110000 PIE2 = %00000000 ' guessing here ADCON1 = %00000111 TRISE = %00000000 CCP1CON = %00000000 Alive: for e = 0 to 3 lcdout $FE, $01 ' wake up display high goled high diagled pause 100 low goled low diagled pause 100 next e ShowRev: ' Read software revision high goled lcdout $FE, $01 ' clear display & write first line for e = 0 to 15 ' read EEROM first 16 places read e,f lcdout f next e lcdout $FE, $C0 ' write second line for e = 16 to 31 ' EEROM locations 17 - 32 read e,f lcdout f next e low goled pause 1500 lcdout $FE, $01, "Looking for", $FE, $C0, "GPS data " serin2 rx232, 188, 2000, nogps,[WAIT("$GPRMC")] lcdout $FE, $01, "GPS found", $FE, $C0, "Loading data" GetData: ProcessRMC: serin2 rx232, 188, 2000, nogps,[WAIT("$GPRMC")] ' find start for i = 0 to 84 ' plenty of length - can be cut back serin2 rx232, 188, [a[i]] next i FindTrackField: CommaCnt = 0 ' lcdout $FE, $01 for i = 0 to 84 e = a[i] if e = "," then CommaCnt = CommaCnt + 1 if CommaCnt = 8 then gettrack 'Track follows 8th comma 'MagVar follows 10th next i GetTrack: track = 0 for j = (i+1) to (i+8) ' get (up to) the next 8 characters if a[j]="," then trackdone ' end of field or blank field found if a[j]<>"." then ' ignore the decimal point e = a[j] - 48 'ASCII representation - subtract 48 to get byte value track = 10* track + e endif next j TrackDone: ' at this point we have Track * 10 if CommaCnt = 10 then ' lcdout $FE, $01, "MagVar ", #track/10, ".", #track//10 serout bootout, 2, [$0D, $0A, "MagVar = ", #track/10, ".", #track//10] else ' lcdout $FE, $01, "Track ", #track/10, ".", #track//10 serout bootout, 2, [$0D, $0A, "Track = ", #track/10, ".", #track//10] endif GetRMBData: ' capture 84 character frame in real time serin2 rx232, 188, 2000, nogps,[WAIT("$GPRMB")] ' find header for i = 0 to 83 'grab data stream serin2 rx232, 188, [a[i]] next i ' now we have an 84 character array starting with the first comma after ' $GPRMB. $GPRMB is of variable length depending on field values. UnpackRMB: ' unpack frame & show on SEROUT CommaCnt = 0 for i = 0 to 83 if a[i] = "," then CommaCnt = CommaCnt + 1 ' found a new field serout bootout, 2, [$0D, $0A, #CommaCnt , ","] if CommaCnt = 1 then getvalidity if CommaCnt = 2 then getxte if CommaCnt = 3 then getsteer if CommaCnt = 4 then getorigin if CommaCnt = 5 then getdestination ' if CommaCnt = 6 then getdestnlatt ' if CommaCnt = 7 then gethemisphere ' if CommaCnt = 8 then getdestlong ' if CommaCnt = 9 then geteorw ' if CommaCnt = 10 then getrangetogo if CommaCnt = 11 then getbearing ' if CommaCnt = 12 then getclosingvelocity if CommaCnt = 13 then getarrival if CommaCnt = 14 then getdata 'all done so get next RMC TossFieldData: ' use this to throw away unwanted fields for j = i+1 to (i+15) 'get the next character if a[j] = "," then goto getnextfield endif serout bootout, 2, [a[j]] next j endif GetNextField: next i goto getdata GetValidity: ' This is needed since both Track and Bearing collapses to 0.0 when no ' GPS data is being received. This could be falsely interpreted as ' traveling due North with the destination dead ahead. ' A FailSafe check must be done here to prevent this. Currently omitted. if a[i+1] = "V" then serout bootout, 2, ["V = bad frame"] goto GetNextField endif if a[i+1] = "A" then serout bootout, 2, [ "A = good frame"] goto GetNextField endif serout bootout, 2, [ "NO sync"] goto GetNextField GetXTE: xte = 0 for j = (i+1) to (i+8) ' get (up to) the next 8 characters if a[j]="," then xtedone ' end of field or blank field found if a[j]<>"." then ' ignore any decimal point e = a[j] - 48 'ASCII representation - subtract 48 to get numeric value xte = 10* xte + e endif next j XTEDone: ' at this point we have XTE * 10 serout bootout, 2, ["XTE = ", #xte/10, ".", #xte//10] goto GetNextField GetSteer: if a[i+1] = "L" then serout bootout, 2, ["Turn LEFT"] goto GetNextField endif if a[i+1] = "R" then serout bootout, 2, [ "Turn RIGHT"] goto GetNextField endif serout bootout, 2, [ "NO turn info"] goto GetNextField GetOrigin: 'This is an alphanumeric field - needs unpacking serout bootout, 2, ["Origin = "] for j = (i+1) to (i+15) ' get (up to) the next 15 characters if a[j]="," then origindone ' end of field or blank field found serout bootout, 2, [ a[j]] next j OriginDone: goto GetNextField GetDestination: 'This is an alphanumeric field - needs unpacking serout bootout, 2, ["Destination = "] for j = (i+1) to (i+15) ' get (up to) the next 15 characters if a[j]="," then destinationdone ' end of field or blank field found serout bootout, 2, [ a[j]] next j DestinationDone: goto GetNextField GetBearing: bearing = 0 for j = (i+1) to (i+8) ' get (up to) the next 8 characters if a[j]="," then bearingdone ' end of field or blank field found if a[j]<>"." then ' ignore any decimal point e = a[j] - 48 'ASCII representation - subtract 48 to get numeric value bearing = 10* bearing + e endif next j BearingDone: ' at this point we have BEARING * 10 serout bootout, 2, ["Bearing = ", #bearing/10, ".", #bearing//10] lcdout $FE, $01, "Track ", #track/10, ".", #track//10 lcdout $FE, $C0, "Bearing ",#bearing/10, ".", #bearing//10 goto GetNextField GetArrival: if a[i+1] = "A" then serout bootout, 2, ["Arrived"] goto GetNextField endif if a[i+1] = "V" then serout bootout, 2, [ "not there yet"] goto GetNextField endif serout bootout, 2, [ "NO arrival info"] goto GetNextField NoGPS: lcdout $FE, $01, "No GPS data " , $FE, $C0, "Check GPS " pause 1000 goto startup ZZZZZ: '$GPRMB 'Recommended minimum navigation information sent by navigation receiver ' ONLY when a destination waypoint is active. 'eg1. $GPRMB,A,0.66,L,003,004,4917.24,N,12309.57,W,001.3,052.5,000.5,V*0B ' A Data status A = OK, V = warning ' 0.66,L Cross-track error (nautical miles, 9.9 max.), ' steer Left to correct (or R = right) ' 003 Origin waypoint ID ' 004 Destination waypoint ID ' 4917.24,N Destination waypoint latitude 49 deg. 17.24 min. N ' 12309.57,W Destination waypoint longitude 123 deg. 09.57 min. W ' 001.3 Range to destination, nautical miles ' 052.5 True bearing to destination ' 000.5 Velocity towards destination, knots ' V Arrival alarm A = arrived, V = not arrived ' *0B mandatory checksum 'eg2. $GPRMB,A,4.08,L,EGLL,EGLM,5130.02,N,00046.34,W,004.6,213.9,122.9,A*3D ' 1 2 3 4 5 6 7 8 9 10 11 12 13 ' 1 A validity ' 2 4.08 off track ' 3 L Steer Left (L/R) ' 4 EGLL last waypoint ' 5 EGLM next waypoint ' 6 5130.02 Latitude of Next waypoint ' 7 N North/South ' 8 00046.34 Longitude of next waypoint ' 9 W East/West ' 10 004.6 Range ' 11 213.9 bearing to waypt. ' 12 122.9 closing velocity ' 13 A arrival alarm ' 14 FAA Mode Indicator ' 15 *3D checksum (in error here) 'eg3. $GPRMB,A,x.x,a,c--c,d--d,llll.ll,e,yyyyy.yy,f,g.g,h.h,i.i,j*kk '1 = Data Status (V=navigation receiver warning) '2 = Crosstrack error in nautical miles '3 = Direction to steer (L or R) to correct error '4 = Origin waypoint ID# '5 = Destination waypoint ID# '6 = Destination waypoint latitude '7 = N or S '8 = Destination waypoint longitude '9 = E or W '10 = Range to destination in nautical miles '11 = Bearing to destination, degrees True '12 = Destination closing velocity in knots '13 = Arrival status; (A=entered or perpendicular passed) '14 = FAA Mode Indicator see below '15 = Checksum '-------------------------------------------------------------------------------- '$GPRMC 'Recommended minimum specific GPS/Transit data 'eg1. $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 'eg2. $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68 ' 225446 Time of fix 22:54:46 UTC ' A Navigation receiver warning A = Valid position, V = Warning ' 4916.45,N Latitude 49 deg. 16.45 min. North ' 12311.12,W Longitude 123 deg. 11.12 min. West ' 000.5 Speed over ground, Knots ' 054.7 Course Made Good, degrees true ' 191194 UTC Date of fix, 19 November 1994 ' 020.3,E Magnetic variation, 20.3 deg. East ' *68 mandatory checksum 'eg3. $GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70 ' 1 2 3 4 5 6 7 8 9 10 11 12 ' 1 220516 Time Stamp ' 2 A validity - A-ok, V-invalid ' 3 5133.82 current Latitude ' 4 N North/South ' 5 00042.24 current Longitude ' 6 W East/West ' 7 173.8 Speed in knots ' 8 231.8 True course ' 9 130694 Date Stamp ' 10 004.2 Variation ' 11 W East/West ' 12 FAA Mode Indicator see below ' 13 *70 checksum 'eg4. for NMEA 0183 version 3.00 active the Mode indicator field is added ' $GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a,m*hh 'Field # '1 = UTC time of fix '2 = Data status (A=Valid position, V=navigation receiver warning) '3 = Latitude of fix '4 = N or S of longitude '5 = Longitude of fix '6 = E or W of longitude '7 = Speed over ground in knots '8 = Track made good in degrees True '9 = UTC date of fix '10 = Magnetic variation degrees (Easterly var. subtracts from true course) '11 = E or W of magnetic variation '12 = Mode indicator, (A=Autonomous, D=Differential, E=Estimated, N=Data not valid) '13 = Checksum 'NOTE there may also be an FAA mode indicator as the last field before the ' checksum. 'In NMEA 2.3, several sentences (APB, BWC, BWR, GLL, RMA, RMB, RMC, 'VTG, WCV, and XTE) got a new last field carrying the signal integrity 'information needed by the FAA. (The values in the GGA mode field were 'extended to carry this information as well.) Here are the values: 'FAA Mode Indicator ' A = Autonomous mode ' D = Differential Mode ' E = Estimated (dead-reckoning) mode ' M = Manual Input Mode ' S = Simulated Mode ' N = Data Not Valid 'This field may be empty. In pre-2.3 versions it is omitted. [NTUM] says 'that according to the NMEA specification, it dominates the Status field -- 'the Status field will be set to "A" (data valid) for Mode Indicators A 'and D, and to "V" (data invalid) for all other values of the Mode 'Indicator. This is confirmed by [IEC]. 'Where a numeric latitude or longitude is given, the two digits 'immediately to the left of the decimal point are whole minutes, to the 'right are decimals of minutes, and the remaining digits to the left of 'the whole minutes are whole degrees.