GPS Parsing Problems
So I keep running into problems with parsing strings. I have a few gps examples, none of them work. just tried moding gps_vga to a gps to serial, no love. if I relay the gps.rx to ser.tx (ser.tx(gps.rx)) i get all the gps info no problem, but it is in its $GGA,1232,1232,1212,2,0*17 form.
Example:
The ONLY thing that Kinda works:
Example:
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
OBJ
'text : "vga_text"
text : "FullDuplexSerial" ' Serial Out instead of TV Out
gps : "GPS_IO_mini"
pub main | gmt
gps.start
text.Start(31, 30, 0, 115200) ' FullDuplexSerial to PC via USB to Serial Module
text.str(string(13,"Loading... "))
repeat
text.tx(00)
text.str((string("Latitude ")))
text.str(gps.latitude)
text.tx(13)
text.str((string("Longitude ")))
text.str(gps.longitude)
text.tx(13)
text.str((string("GPS Altitude ")))
text.str(gps.GPSaltitude)
text.tx(13)
text.str((string("Speed ")))
text.str(gps.speed)
text.tx(13)
text.str((string("Satellites ")))
text.str(gps.satellites)
text.tx(13)
text.str((string("Time GMT ")))
text.str(gps.time)
text.tx(13)
text.str((string("Date ")))
text.str(gps.date)
text.tx(13)
text.str((string("Heading ")))
text.str(gps.heading)
text.str((string(" ")))
text.str(gps.N_S)
text.str(gps.e_w)
text.tx(13)
waitcnt(1_000_000_0 + cnt)
'' *****************************
'' GPS routines
'' (c) 2007 Perry James Mole
'' pjm@ridge-communications.ca
'' *****************************
' PVH Comment - Excellent small GPS reader routines.
' $GPRMC Recommended minimum data ie: $GPRMC,081836,A,3751.6565,S,14507.3654,E,000.0,360.0,130998,011.3,E*62
' $GPGGA GPS Fix Data ie: $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75
' $PGRMZ eTrex proprietary barametric altitude ft ie: $PGRMZ,453,f,2*18
CON
CR = 13 ' ASCII <CR>
LF = 10 ' ASCII <LF>
serXmit = 0 ' Serial Transmit on mouse
serRecv = 1 ' Serial Receive on mouse
GPSrx = 12
GPStx = 13
VAR
long gps_stack[10]
byte GPRMCb[68],GPGGAb[80],PGRMZb[40]
long GPRMCa[20],GPGGAa[20],PGRMZa[20]
byte gps_buff[80],Rx',cksum
long cog,cptr,ptr,arg,j
long Null[1]
OBJ
uart : "FullDuplexSerial_mini"
PUB start : okay
'' Starts uart object (at baud specified) in a cog
'' -- returns false if no cog available
'okay := uart.start(GPSrx, GPStx, 1, 4800)
okay := uart.start(GPSrx, GPStx, 0, 57600) ' My GPS is steup for 57600
return cog := cognew(readNEMA,@gps_stack) + 1
PUB readNEMA
Null[0] := 0
repeat
longfill(gps_buff,20,0)
repeat while Rx <>= "$" ' wait for the $ to insure we are starting with
Rx := uart.rx ' a complete NMEA sentence
cptr := 0
repeat while Rx <>= CR ' continue to collect data until the end of the NMEA sentence
Rx := uart.rx ' get character from Rx Buffer
if Rx == ","
gps_buff[cptr++] := 0 ' If "," replace the character with 0
else
gps_buff[cptr++] := Rx ' else save the character
if gps_buff[2] == "G"
if gps_buff[3] == "G"
if gps_buff[4] == "A"
copy_buffer(@GPGGAb, @GPGGAa)
if gps_buff[2] == "R"
if gps_buff[3] == "M"
if gps_buff[4] == "C"
copy_buffer(@GPRMCb, @GPRMCa)
if gps_buff[0] == "P"
if gps_buff[1] == "G"
if gps_buff[2] == "R"
if gps_buff[3] == "M"
if gps_buff[4] == "Z"
copy_buffer(@PGRMZb, @PGRMZa)
pub copy_buffer ( buffer,args)
bytemove(buffer,@gps_buff,cptr) ' copy received data to buffer
ptr := buffer
arg := 0
repeat j from 0 to 78 ' build array of pointers
if byte[ptr] == 0 ' to each
if byte[ptr+1] == 0 ' record
long[args][arg] := Null ' in
else ' the
long[args][arg] := ptr+1 ' data buffer
arg++
ptr++
' now we just need to return the pointer to the desired record
pub altitude
return PGRMZa[0]
pub valid
return GPRMCa[1]
pub speed
return GPRMCa[6]
pub heading
return GPRMCa[7]
pub date
return GPRMCa[8]
pub GPSaltitude
return GPGGAa[8]
pub time
return GPGGAa[0]
pub latitude
return GPGGAa[1]
pub N_S
return GPGGAa[2]
pub longitude
return GPGGAa[3]
pub E_W
return GPGGAa[4]
pub satellites
return GPGGAa[6]
pub hdop
return GPGGAa[7]
'pub vdop
' return GPGSAa[14]
The ONLY thing that Kinda works:
Pub Start
ser.start(31, 30, 0, 115200)
gps.start(GPSrx, GPStx, 0, 57600)
repeat
ser.tx(gps.rx)

Comments
check post #66 if it applies to you
http://forums.parallax.com/showthread.php/136417-Interfacing-to-the-tacktick-NMEA-unit/page4
Massimo
i know its gotta be something simple that i am just over looking.
Zack
The Original:
'' ================================================================================================= '' '' File....... gps_basic_demo.spin '' Purpose.... Demonstrates basic use of gps_basic object '' Author..... '' E-mail..... '' Started.... '' Updated.... 19 FEB 2011 '' '' ================================================================================================= con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 ' use 5MHz crystal ' _xinfreq = 6_250_000 ' use 6.25MHz crystal CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq MS_001 = CLK_FREQ / 1_000 US_001 = CLK_FREQ / 1_000_000 con RX1 = 31 ' programming port TX1 = 30 SDA = 29 ' boot EEPROM SCL = 28 GPS_RX = 12 ' GPS input (connect to GPS TX) con PST = -8 ' US time zone offsets MST = -7 CST = -6 EST = -5 con #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR ' PST formmatting control #14, GOTOX, GOTOY, CLS obj gps : "gps_basic" ' gps input term : "fullduplexserial" ' for terminal comms dat screen byte "============================", CR byte " GPS Demo ", CR byte "============================", CR byte CR byte "GPS Fix........ ", CR byte "Satellites..... ", CR byte CR byte "UTC time....... ", CR byte "Local time..... ", CR byte "Latitude....... ", CR byte "Longitude...... ", CR byte "Altitude (M)... ", CR byte 0 pub main | sync, ok 'gps.startx(GPS_RX, PST, 9600, 1250) ' Parallax #28505 'gps.startx(GPS_RX, PST, -4800, 2500) ' for Garmin eTrex gps.startx(GPS_RX, MST, 57600, 2500) term.start(RX1, TX1, %0000, 115_200) ' start terminal comms waitcnt(clkfreq / 500 + cnt) ' let objects start term.tx(CLS) ' clean-up terminal term.str(@screen) waitcnt(clkfreq << 1 + cnt) ' let gps buffers fill sync := cnt ' create sync for refreshes repeat if (gps.hasgps == false) ' connected? term.tx(CLS) ' no, reset screen term.str(@screen) moveto(16, 4) term.str(string("No GPS")) ' display no-connect msg else moveto(16, 4) term.str(gps.s_gpsfix) ' gps quality (fix) term.tx(CLREOL) ok := gps.n_gpsfix ' flag for other fields moveto(16, 5) term.str(gps.s_satellites) term.tx(CLREOL) moveto(16, 7) term.str(gps.fs_utc_time) term.tx(CLREOL) moveto(16, 8) term.str(gps.fs_local_time) term.tx(CLREOL) moveto(16, 9) term.tx(" ") term.str(gps.s_latitude) term.tx(CLREOL) moveto(16, 10) term.str(gps.s_longitude) term.tx(CLREOL) moveto(16, 11) term.str(gps.s_altm) term.tx(CLREOL) waitcnt((clkfreq >> 3) + cnt) ' refresh 8x per second pub moveto(x, y) '' Position PST cursor at x/y term.tx(GOTOXY) term.tx(x) term.tx(y) dat {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }}My Version:
'' ================================================================================================= '' '' File....... gps_basic_demo.spin '' Purpose.... Demonstrates basic use of gps_basic object '' Author..... '' E-mail..... '' Started.... '' Updated.... 19 FEB 2011 '' '' ================================================================================================= con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 ' use 5MHz crystal ' _xinfreq = 6_250_000 ' use 6.25MHz crystal CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq MS_001 = CLK_FREQ / 1_000 US_001 = CLK_FREQ / 1_000_000 con RX1 = 31 ' programming port TX1 = 30 SDA = 29 ' boot EEPROM SCL = 28 GPS_RX = 12 ' GPS input (connect to GPS TX) con PST = -8 ' US time zone offsets MST = -7 CST = -6 EST = -5 con #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR ' PST formmatting control #14, GOTOX, GOTOY, CLS obj gps : "gps_basic" ' gps input term : "fullduplexserial" ' for terminal comms fm : "FloatMath" ' 0 Cog f : "FloatString" ' 0 Cog var long Altitude, Fix, Speed, Heading, Time, Valid ' GPS Info long Latitude, N_S, Longitude, E_W, Satellites ' GPS Info pub main | sync, ok 'gps.startx(GPS_RX, PST, 9600, 1250) ' Parallax #28505 'gps.startx(GPS_RX, PST, -4800, 2500) ' for Garmin eTrex gps.startx(GPS_RX, MST, 57600, 2500) term.start(RX1, TX1, %0000, 115_200) ' start terminal comms waitcnt(clkfreq / 500 + cnt) ' let objects start waitcnt(clkfreq << 1 + cnt) ' let gps buffers fill sync := cnt ' create sync for refreshes repeat if (gps.hasgps == false) ' connected? term.tx(CLS) ' no, reset screen term.str(string("No GPS")) ' display no-connect msg else Valid := GPS.hasgps Fix := GPS.n_gpsfix Satellites := GPS.n_satellites Time := GPS.s_local_time Latitude := GPS.s_latitude Longitude := GPS.s_longitude Altitude := GPS.n_altf ' Altitude in Feet Speed := GPS.n_speedm Heading := GPS.n_bearing term.str(string("$GPS")) ' GPS term.str(string(",")) term.dec(Satellites) term.str(string(",")) term.dec(Fix) term.str(string(",")) term.dec(Time) term.str(string(",")) term.dec(Altitude) term.str(string(",")) term.dec(Speed) term.str(string(",")) term.dec(Heading) term.str(string(",")) term.dec(Latitude) term.str(string(",")) 'term.dec(GPS.N_S) 'term.str(string(",")) term.dec(Longitude) 'term.str(string(",")) 'term.dec(GPS.E_W) term.tx(13) waitcnt((clkfreq >> 3) + cnt) ' refresh 8x per second pub moveto(x, y) '' Position PST cursor at x/y term.tx(GOTOXY) term.tx(x) term.tx(y) dat {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }}'' ================================================================================================= '' '' File....... gps_basic.spin '' Purpose.... Basic GPS parsing -- string and numeric forms '' Author..... Jon "JonnyMac" McPhalen '' -- see below for terms of use '' E-mail..... '' Started.... '' Updated.... 19 FEB 2011 '' '' ================================================================================================= { Notes: Consumes two cogs -- half-duplex uart for receiving characters from GPS -- parser for extracting select GPS strings from steam Resources: -- http://aprs.gids.nl/nmea -- http://home.mira.net/~gnb/gps/nmea.html } con RX1 = 31 ' programming port TX1 = 30 SDA = 29 ' boot EEPROM SCL = 28 con BUF_SIZE = 128 ' rx buffer (power of 2) WORK_SIZE = 80 ' for working buffers RSLT_SIZE = 20 ' temp result string HMS_SEP = ":" ' hrs-mins-secs separator DMY_SEP = "/" ' day-month-year separator var long hasgpsflag ' gps detected long utcoffset long parsecog long stack[32] ' for parsing cog long rxcog long rxpin ' rx pin (from gps) long rxtix ' ticks per bit @ 4800 long rxhead ' head pointer long rxtail ' tail pointer long rxbufaddr ' address of rx buffer long rxtimeout ' max wait for serial data (ms) byte rxbuf[BUF_SIZE] ' receive buffer (32 longs) byte gpswork[WORK_SIZE] ' working buffers byte rmcwork[WORK_SIZE] byte ggawork[WORK_SIZE] byte gpsrslt[RSLT_SIZE] ' result string dat RMC_HDR byte "GPRMC,", 0 GGA_HDR byte "GPGGA,", 0 pub start(rxd, utcofs) '' Starts RX and GPS parser cogs '' -- uses default 4800 baud, true mode comms '' -- uses default timeout for 2-sec updates return startx(rxd, utcofs, 4_800, 2_500) pub startx(rxd, utcofs, baud, timeout) '' Starts RX and GPS parser cogs '' -- allows user-specified baud rate (negative for inverted baud mode) '' -- allows user-specified serial timeout (ms) stop rxpin := rxd ' assign pin rxtix := clkfreq / baud ' assign baud rxbufaddr := @rxbuf[0] ' locate buffer rxtimeout := timeout utcoffset := -23 #> utcofs <# 23 ' set offset rxcog := cognew(@rxserial, @rxpin) + 1 ' start rx uart cog if rxcog parsecog := cognew(parse_gps, @stack) + 1 ' start parser cog return (rxcog) and (parsecog) pub stop '' Stops previously-loaded cogs and flushes buffers if rxcog ' if running cogstop(rxcog~ - 1) if parsecog cogstop(parsecog~ - 1) longfill(@rxhead, 0, 2) ' flush buffers bytefill(@rxbuf, 0, BUF_SIZE) bytefill(@gpsrslt, 0, RSLT_SIZE) pub hasgps '' Returns true when UART actively receiving characters return hasgpsflag pub s_gpsfix '' Returns GPS fix quality as z-string case n_gpsfix ' from dec to string 0 : bytemove(@gpsrslt, string("Invalid"), 8) 1 : bytemove(@gpsrslt, string("GPS"), 4) 2 : bytemove(@gpsrslt, string("DGPS"), 5) return @gpsrslt ' return pointer pub n_gpsfix '' Returns GPS fix quality '' -- 0 = invalid, 1 = GPS fix, 2 = DGPS fix bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear workspace if (strncmp(@GGA_HDR, @ggawork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @ggawork, 6) ' yes, get fix field return str2dec(@gpsrslt, 1) ' return fix pub s_satellites '' Returns satellites in view as z-string, "0".."??" bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@GGA_HDR, @ggawork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @ggawork, 7) ' yes, get sats field return @gpsrslt ' return pointer pub n_satellites '' Returns satellites in view as decimal value, 0..?? s_satellites return str2dec(@gpsrslt, 2) ' return satellites pub s_utc_time '' UTC time as z-string: "HHMMSS" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' get time field gpsrslt[6] := 0 ' terminate (no ms) return @gpsrslt ' return pointer pub fs_utc_time '' UTC time as formatted z-string: "HH:MM:SS" '' -- returns pointer to result string s_utc_time ' get time field if (gpsrslt > 0) ' if not empty s_insert(HMS_SEP, 4, @gpsrslt) ' separate secs s_insert(HMS_SEP, 2, @gpsrslt) ' separate mins gpsrslt[8] := 0 ' terminate (no ms) return @gpsrslt ' return pointer pub s_local_time | hr '' Local time as z-string: "HHMMSS" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' get time field hr := str2dec(@gpsrslt, 2) ' get utc hours hr := (hr + (24 + utcoffset)) // 24 ' add utc offset gpsrslt[0] := (hr / 10) + "0" ' convert back to string gpsrslt[1] := (hr // 10) + "0" gpsrslt[6] := 0 ' terminate (no ms) return @gpsrslt ' return pointer pub fs_local_time '' Local time as formated z-string: "HH:MM:SS" '' -- returns pointer to result string s_local_time ' get time string if (gpsrslt > 0) ' if not empty s_insert(HMS_SEP, 4, @gpsrslt) ' separate secs s_insert(HMS_SEP, 2, @gpsrslt) ' separate mins gpsrslt[8] := 0 ' terminate (no ms) return @gpsrslt ' return pointer pub s_utc_hrs '' UTC hours as z-string: "00".."23" (UTC time) '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' get time field gpsrslt[2] := 0 ' terminate return @gpsrslt ' return pointer pub n_utc_hrs '' UTC hours as decimal value, 0..23 '' -- returns -1 if gps string is invalid s_utc_hrs ' get hours if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[2], 2) ' convert else return -1 ' error pub s_local_hrs | hr '' Local hours as z-string: "00".."23" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' yes, get time field hr := str2dec(@gpsrslt, 2) ' get utc hours hr := (hr + (24 + utcoffset)) // 24 ' add utc offset gpsrslt[0] := (hr / 10) + "0" ' convert back to string gpsrslt[1] := (hr // 10) + "0" gpsrslt[2] := 0 ' terminate return @gpsrslt ' return pointer pub n_local_hrs '' Local hours as decimal value, 0..23 '' -- returns -1 if gps string is invalid s_local_hrs ' get hours if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[2], 2) ' convert to dec else return -1 ' error pub s_mins '' (Current time) Minutes as z-string: "00".."59" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' yes, get time field bytemove(@gpsrslt[0], @gpsrslt[2], 2) ' yes, copy minutes gpsrslt[2] := 0 ' terminate return @gpsrslt ' return pointer pub n_mins '' (Current time) Minutes as decimal value, 0..59 '' -- returns -1 if gps string is invalid s_mins ' get minutes if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[2], 2) ' convert seconds else return -1 ' error pub s_secs '' Seconds as z-string: "00".."59" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 1) ' yes, get time field bytemove(@gpsrslt, @gpsrslt[4], 2) ' yes, copy seconds return @gpsrslt ' return pointer pub n_secs '' Seconds as decimal value, 0..59 '' -- returns -1 if gps string is invalid if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? return str2dec(@rmcwork[11], 2) ' yes, convert seconds else return -1 ' no, error pub s_date '' Current date as z-string: "DDMMYY" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 9) ' yes, get date field return @gpsrslt ' return pointer pub fs_date '' Current date as formatted z-string: "DD/MM/YY" '' -- returns pointer to result string s_date ' get date field if (gpsrslt[0] > 0) ' if not empty s_insert(DMY_SEP, 4, @gpsrslt) ' separate year s_insert(DMY_SEP, 2, @gpsrslt) ' separate month return @gpsrslt ' return pointer pub s_day '' Current day as z-string: "01".."31" '' -- returns pointer to result string s_date ' get date field gpsrslt[2] := 0 ' terminate after day return @gpsrslt ' return pointer pub n_day '' Current day as decimal value, 1..31 '' -- returns -1 if gps string is invalid s_date ' get date field if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[0], 2) ' return day else return -1 ' error pub s_month '' Current month as z-string: "01".."12" '' -- returns pointer to result string s_date ' get date field bytemove(@gpsrslt, @gpsrslt[2], 2) ' move month gpsrslt[2] := 0 ' terminate return @gpsrslt ' return pointer pub n_month '' Current month as decimal value, 1..12 '' -- returns -1 if gps string is invalid s_month ' get month string if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[0], 2) ' return month else return -1 ' error pub s_year '' Current year as z-string: "00".."99" '' -- returns pointer to result string s_date ' get date field bytemove(@gpsrslt, @gpsrslt[4], 2) ' move year gpsrslt[2] := 0 ' terminate return @gpsrslt ' return pointer pub n_year '' Current month as decimal value, 0..99 '' -- returns -1 if gps string is invalid s_year ' get year string if (gpsrslt[0] > 0) ' if not empty return str2dec(@gpsrslt[0], 2) ' return year else return -1 ' error pub s_latitude '' Latitude as z-string in the form "ddmm.ssss X" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 3) ' get latitude field gpsrslt[9] := " " ' remove termination gps_fcopy(@gpsrslt[10], @rmcwork, 4) ' get hemisphere return @gpsrslt ' return pointer pub n_latsign '' Returns hemisphere as number '' -- 1 for N, -1 for S s_latitude ' get latitude if (gpsrslt[10] == "S") ' check hemisphere return -1 else return 1 pub s_latd '' Latitude degrees as z-string in the form "00".."90" '' -- returns pointer to result string s_latitude ' get latitude gpsrslt[2] := 0 ' terminate after degrees return @gpsrslt ' return pointer pub n_latd '' Latitude degrees as decimal value, 0..90 s_latitude ' get latitude return str2dec(@gpsrslt, 2) ' extract degrees pub s_latm '' Latitude minutes as z-string in the form "00".."59" '' -- returns pointer to result string s_latitude ' get latitude bytemove(@gpsrslt[0], @gpsrslt[2], 2) ' extract minutes gpsrslt[2] := 0 ' terminate after minutes return @gpsrslt ' return pointer pub n_latm '' Latitude minutes as decimal value, 0..59 s_latitude ' get latitude return str2dec(@gpsrslt[2], 2) ' extract minutes pub n_lats '' Latitude seconds as decimal value, 0..59 s_latitude ' get latitude return str2dec(@gpsrslt[5], 4) * 60 / 10_000 ' return seconds pub s_longitude '' Longitude as z-string in the form "dddmm.ssss X" '' -- returns pointer to result string bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result if (strncmp(@RMC_HDR, @rmcwork, 6) == 0) ' have gps data? gps_fcopy(@gpsrslt, @rmcwork, 5) ' get latitude field gpsrslt[10] := " " ' remove termination gps_fcopy(@gpsrslt[11], @rmcwork, 6) ' get hemisphere return @gpsrslt ' return pointer pub n_lonsign '' Longitude direction as value '' -- 1 for E, -1 for W s_longitude ' get latitude if (gpsrslt[11] == "W") ' check direction return -1 else return 1 pub s_lond '' Longitude degrees as z-string in the form "000".."180" '' -- returns pointer to result string s_longitude ' get latitude gpsrslt[3] := 0 ' terminate after degrees return @gpsrslt ' return pointer pub n_lond '' Longitude degrees as decimal value, 0..180 s_longitude ' get latitude return str2dec(@gpsrslt, 3) ' extract degrees pub s_lonm '' Longitude minutes as z-string in the form "00".."59" '' -- returns pointer to result string s_longitude ' get latitude bytemove(@gpsrslt[0], @gpsrslt[3], 3) ' extract minutes gpsrslt[2] := 0 ' terminate after minutes return @gpsrslt ' return pointer pub n_lonm '' Longitude minutes as decimal value, 0..59 s_longitude ' get latitude return str2dec(@gpsrslt[3], 2) ' extract minutes pub n_lons '' Longitude seconds as decimal value, 0..59 s_longitude ' get latitude return str2dec(@gpsrslt[6], 4) * 60 / 10_000 ' return seconds pub s_speedk '' Speed in knots as z-string: "0.0".."999.9" bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result gps_fcopy(@gpsrslt, @rmcwork, 7) ' get field 7 return @gpsrslt ' return pointer pub n_speedk | p '' Speed in 0.1 knots as decimal value, 0..9999 s_speedk ' get speed string p := instr(@gpsrslt, ".") ' find dpoint if (p => 0) gpsrslt[p] := gpsrslt[p+1] ' move tenths char gpsrslt[p+1] := 0 ' terminate return str2dec(@gpsrslt, 4) ' return 0.1 knots pub n_speedm '' Speed in 0.1 mph as decimal value, 0..~8,689 '' -- 1 mph = 0.868976242 knots return (n_speedk * 868_976 / 1_000_000) ' convert to 0.1 mph pub s_bearing '' Bearing in degrees as z-string: "0.0".."359.9" bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result gps_fcopy(@gpsrslt, @rmcwork, 8) ' get field 8 return @gpsrslt ' return pointer pub n_bearing | p '' Bearing in 0.1 degrees as decimal value, 0..3599 s_bearing ' get bearing string p := instr(@gpsrslt, ".") ' find dpoint if (p => 0) gpsrslt[p] := gpsrslt[p+1] ' move tenths char gpsrslt[p+1] := 0 ' terminate return str2dec(@gpsrslt, strsize(@gpsrslt)) ' return bearing pub s_altm '' Altitude in meters as z-string, "0.0".."9999.9" bytefill(@gpsrslt, 0, RSLT_SIZE) ' clear result gps_fcopy(@gpsrslt, @ggawork, 9) ' get field 9 return @gpsrslt ' return pointer pub n_altm | len '' Altitude in 0.1 meters as decimal value, 0..99999 s_altm ' get altitude string len := strsize(@gpsrslt) ' get length gpsrslt[len-2] := gpsrslt[len-1] ' remove decimal point gpsrslt[len-1] := 0 ' terminate return str2dec(@gpsrslt, 6) ' return 0.1 meters pub n_altf '' Altitude in 0.1 feet as decimal value, 0..~30480 '' -- 1 foot = 0.3048 meters return (n_altm * 3_048 / 10_000) ' return 0.1 feet pub rslt_pntr '' Returns pointer to GPS result string '' -- allows access for external applications return @gpsrslt pub rslt_copy(dest) '' Copies contents of result string to destination '' -- allows parent object to make copy of last result bytemove(dest, @gpsrslt, strsize(@gpsrslt)) return dest ' return pointer pub str2dec(spntr, n) | dec, c '' Returns [positive] decimal value of string at spntr dec := 0 ' initialize result repeat n c := byte[spntr++] ' get character if (c < "0") or (c > "9") ' if non digit quit else dec *= 10 ' adjust for new digit dec += (c - "0") ' add new digit return dec ' return result pri gps_fcopy(dest, src, fn) | idx1, idx2, c '' Copies gps string in (0-indexed) field number (fn) from src to dest idx1 := field_idx(fn, src) ' find start idx2 := 0 if (idx1 => 0) ' if valid repeat ' copy field c := byte[src][idx1++] ' get source character if (c <> ",") and (c <> "*") and (c <> 13) ' if not field terminator byte[dest][idx2++] := c ' add to destination else quit else idx2 := 0 ' empty strin on invalid field # byte[dest][idx2] := 0 ' add string terminator return dest ' return result pntr pri field_idx(fn, spntr) | idx, c '' Returns position index of field number, fn (0+) idx := 0 if (fn > 0) ' if not 1st field repeat while fn c := byte[spntr][idx++] if (c == ",") ' if separator fn -= 1 ' update field count if (c == "*") or (c == 13) ' if end of string idx := -1 ' error quit return idx pri s_insert(c, pos, spntr) | idx '' Inserts c at pos in string at spntr '' -- string should be shorter than buffer by at least one character repeat idx from strsize(spntr) to pos ' work backward byte[spntr][idx+1] := byte[spntr][idx] ' create space byte[spntr][pos] := c ' insert character pri strncopy(dest, src, n) | c '' Copies (up to) n characters from src to dest '' -- terminates on 0 or CR for GPS strings repeat n c := byte[src++] ' get byte from source if (c == 13) or (c == 10) ' CR and LF to 0 c := 0 byte[dest++] := c ' copy to destination if (c == 0) ' if at end quit ' quit pri strncmp(s1, s2, n) | idx '' Compare strings, up to n characters '' -- will terminate on 0 in string(s) repeat idx from 0 to n-1 ' loop through length if (byte[s1][idx] == byte[s2][idx]) ' if chars equal if (byte[s1][idx] == 0) or (idx == n-1) ' if at end return 0 ' return equality else quit ' no, exit return byte[s1][idx] - byte[s2][idx] ' return comparison pri instr(str, c) | len, pos '' Returns position of c in string '' -- if not found len := strsize(str) pos := 0 repeat len if (byte[str++] == c) quit else pos += 1 if (pos < len) return pos else return -1 pri parse_gps | ok, c, len '' Pulls characters from UART buffer, moves to target GPS buffer '' -- runs in separate cog; do not call as standard method repeat ok := true ' assume ok bytefill(@gpswork, 0, WORK_SIZE) ' clear workspace repeat c := rxtime(rxtimeout) ' get char from stream if (c < 0) ' if timeout ok := false ' mark as bad quit ' abort until (c == "$") ' done when $ located if ok ' if no timeout len := 0 ' reset string length repeat c := rxtime(rxtimeout) ' get char from stream if (c < 0) ' if timeout ok := false ' mark as bad quit ' abort if (c <> 13) ' if at end gpswork[len++] := c ' move to workspace else quit if ok ' if no timeout if (strncmp(@RMC_HDR, @gpswork, 6) == 0) ' $GPRMC string? bytemove(@rmcwork, @gpswork, len) ' yes, move to buffer elseif (strncmp(@GGA_HDR, @gpswork, 6) == 0) ' $GPGGA string? bytemove(@ggawork, @gpswork, len) ' yes, move to buffer pri rxtime(ms) | t, c '' Pulls c from receive buffer if available within ms milliseconds '' -- will return -1 if nothing in buffer (e.g., GPS disconnected) '' -- updates global hasgps flag t := cnt repeat until ((c := rx) => 0) or ((cnt - t) / (clkfreq / 1_000) > ms) hasgpsflag := (c => 0) ' mark availability flag return c pri rx | c '' Pulls c from receive buffer if available '' -- returns -1 if buffer empty c := -1 ' assume empty if (rxtail <> rxhead) ' if char available c := rxbuf[rxtail] ' get it rxtail := (rxtail + 1) & (BUF_SIZE-1) ' update tail pointer return c dat org 0 rxserial mov dira, #0 ' all inputs mov tmp1, par ' start of parameters rdlong tmp2, tmp1 ' get rx pin mov rxmask, #1 ' create pin mask shl rxmask, tmp2 add tmp1, #4 rdlong rxbit1x0, tmp1 ' read ticks/bit cmps rxbit1x0, #0 wc ' check for inverted muxc mflag, #1 ' save mode abs rxbit1x0, rxbit1x0 ' remove sign mov rxbit1x5, rxbit1x0 ' create ticks/1.5 bits shr rxbit1x5, #1 add rxbit1x5, rxbit1x0 add tmp1, #4 mov rxheadpntr, tmp1 ' save addres of rxhead add tmp1, #8 ' skip over tails rdlong rxbufpntr, tmp1 ' save addres of rxbuf[0] receive mov rxwork, #0 ' clear work var mov rxcount, #8 ' rx eight bits mov rxtimer, rxbit1x5 ' set timer to 1.5 bits waitstart test mflag, #1 wz ' check mode if_z waitpne rxmask, rxmask ' wait for falling edge if_nz waitpeq rxmask, rxmask ' wait for rising edge add rxtimer, cnt ' sync with system counter rxbit waitcnt rxtimer, rxbit1x0 ' hold for middle of bit test rxmask, ina wc ' rx --> c shr rxwork, #1 ' prep for new bit muxc rxwork, #%1000_0000 ' c --> rxwork.7 djnz rxcount, #rxbit ' update bit count waitcnt rxtimer, #0 ' let last bit finish if_nz xor rxwork, #$FF ' invert if needed putbuf rdlong tmp1, rxheadpntr ' tmp1 := rxhead add tmp1, rxbufpntr ' tmp1 := rxbuf[rxhead] wrbyte rxwork, tmp1 ' rxbuf[rxhead] := rxwork sub tmp1, rxbufpntr ' tmp1 := rxhead add tmp1, #1 ' inc tmp1 and tmp1, #(BUF_SIZE-1) ' wrap around if needed wrlong tmp1, rxheadpntr ' rxhead := tmp1 jmp #receive ' ------------------------------------------------------------------------------------------------- mflag long 0 ' mode flag (1 = inverted) rxmask res 1 ' mask for rx pin rxbit1x0 res 1 ' ticks per bit rxbit1x5 res 1 ' ticks per 1.5 bits rxheadpntr res 1 ' address of head position rxbufpntr res 1 ' address of rxbuf[0] rxwork res 1 ' rx byte input rxcount res 1 ' bits to receive rxtimer res 1 ' timer for bit sampling tmp1 res 1 tmp2 res 1 fit $1F0 dat {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }}using
Latitude := GPS.str2dec(GPS.s_latitude, strsize(GPS.s_latitude)) Longitude := GPS.str2dec(GPS.s_longitude, strsize(GPS.s_longitude))I know the output from AN002 is good. I need to be able to access the info with the mcu, not just ser.str out it.