Data Freshness Test
Hello all,
I've been bumping on this on all afternoon - I'd like to determine if my GPS becomes unplugged from my propeller. I am using Perry's excellent GPS_IO_mini routines in their own cog to collect the GPS strings into memory. So far so good.
However, if the GPS disconnects, the data (with no surprise) does not update. However, the values in memory from the last good run are retained, including the "GPS is valid" byte, despite the fact that this is no longer a true statement.
So! I am comparing the GPS clock data value Time-now (Tnow) with Time-past (Tpast) every second. If they are the different, then the GPS is updating. If the same, then there is problem, and an LED should flash.
Unfortunately, it always shows them as equal. I beleive the problem is in my BYTEMOVE, but have not progressed.
The GPS string data is in the fixed format "131522" for 1pm, 15min, 22 secs, and is properly zero terminated, and the GPS updates at 1Hz, so 2sec is plenty to show a change every time.
Any Ideas?
thanks,
Paul
.
Post Edited (Paul H) : 3/12/2008 10:44:32 PM GMT
I've been bumping on this on all afternoon - I'd like to determine if my GPS becomes unplugged from my propeller. I am using Perry's excellent GPS_IO_mini routines in their own cog to collect the GPS strings into memory. So far so good.
However, if the GPS disconnects, the data (with no surprise) does not update. However, the values in memory from the last good run are retained, including the "GPS is valid" byte, despite the fact that this is no longer a true statement.
So! I am comparing the GPS clock data value Time-now (Tnow) with Time-past (Tpast) every second. If they are the different, then the GPS is updating. If the same, then there is problem, and an LED should flash.
Unfortunately, it always shows them as equal. I beleive the problem is in my BYTEMOVE, but have not progressed.
The GPS string data is in the fixed format "131522" for 1pm, 15min, 22 secs, and is properly zero terminated, and the GPS updates at 1Hz, so 2sec is plenty to show a change every time.
Any Ideas?
thanks,
Paul
repeat
Tnow := gps.time ' pull time data from memory (which works great)
if Tpast <> Tnow ' data is different => FRESH data
fresh := 0
'Tpast := Tnow
bytemove(@Tpast,@Tnow,6) ' move value in current to old for next run
else ' time is the SAME = STALE data
fresh++ ' we will check over 4 seconds to make sure
Clock.WaitSyncMSec(1000) ' wait for 2 second and check again.
' PART 2 What to do with Stale data?
if fresh > 4 ' confirmed STALE data
toggle(27) ' FLASH when STALE
.
Post Edited (Paul H) : 3/12/2008 10:44:32 PM GMT

Comments
Sorry for the goofiness from the text size, the [noparse][[/noparse] 5] bit me when I didn't include the space.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
Post Edited (Paul Baker (Parallax)) : 3/12/2008 11:08:09 PM GMT
It might be a better idea to fix the bug in my code!
on another thread there was found a big mistake i.e. one line should have read longfill(@gps_buff,0,20)
previously it did nothing, but should have cleared the input buffer. This might even solve your problem
I have done some other work to make the code more robust.
I have a newer version but you will have to modify it for your GPS
Perry
I've recently been working with Perry's wonderful GPS code as well. Another way to compare the old time and the current time are to cast them as ints. I don't have my code in front of me, but I can send you the details tomorrow. To do this requires the Numbers object (Num.FromStr(Tnow) should work), but once the current time is a decimal number, you can compare them numerically rather than as strings (as Paul suggests). This will let you know if the time tag is stale without the trouble of stale tags looking good every 10 seconds.
Peter
@Perry - Once I had figured out my issue, I was planning on adding it into my gps_IO_ code, but a timed-interval memory clear would actually be the most straightforward method! I'll get right on it. Is the latest posted on the OBEX if not, please drop a copy here. As it turns out, I no longer have the specific Garmin GPS that I had used with the unique barometric altitude string. Err, well I should say I don't have ALL of that particular GPS... the old saying "What goes up must come down" applies particularly harshly to model airplanes !
@Peter - Good thinking. With my slow refresh (1Hz) I don't have to worry that the cog will be busy to convert to a number.
Awesome - I now have 3 ways to make it work
Paul
that old data is better than no data, as long as you know its age!
So instead of zeroing the data, I am now saving the last valid-data
time and I am in the process of trying to calculate the age in
minutes/seconds since the last good data.
I also found this link www.circuitcellar.com/library/print/1000/Stefan123/4.htm
and hope to add some functions to calculate distances from the data.
Perry gave us a really good start! -Chuck-
.
I think the following should get your hhmmss string into a number. You can simply compare it to Tnow to see if the time has changed, or break it apart into hours, minutes, seconds for calculating the number of seconds since last lock. To do that requires something like this. The following few lines are not tested. I don't see a round/floor/trunc function that works on any thing but constants but my guess is that fractional parts of numbers would simply be dropped when dealing with ints, but I don't know that for sure.
hours := Tnow / 10,000
minutes := ( Tnow - ( hours * 10,000 ) ) / 100
seconds := ( Tnow - ( hours * 10,000 ) ) - ( minutes * 100 )
That could easily be converted into seconds. Come to think of it, you may be better off pulling hours, minutes, and seconds from the HHMMSS string if such a thing is allowed.
hours := Tnow[noparse][[/noparse]5-4]
min := Tnow[noparse][[/noparse]3-2]
sec := Tnow[noparse][[/noparse]1-0]
You'd then have to convert those from strings to decimals. The code below is a stripped down version of what I've been using. I modified Perry's code to parse the incoming serial stream on commas or decimals by changing
if Rx == ","
TO
if Rx == "," OR Rx == "."
AND changed the names of some of his function calls.
{{Convert GPS string to decimal This Object calls several other objects. Use Perry's GPS_IO_mini code and FullDuplexSerial Numbers }} CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 OBJ Num : "Numbers" 'Include Numbers object for writing numbers to terminal GPS : "GPS_IO_mini" VAR long utc, lat1, lat2, lon1, lon2, alt1, alt2, qual, sv, hdop1, hdop2 PUB Main GPS.start Num.Init 'Initialize Numbers ' UTC TIME utc := GPS.time utc := Num.FromStr(utc,Num#DEC) ' LATITUDE lat1 := GPS.lat_DDMM lat1 := Num.FromStr(lat1,Num#DEC) lat2 := GPS.lat_mmmm lat2 := Num.FromStr(lat2,Num#DEC) ' LONGITUDE lon1 := GPS.lon_DDDMM lon1 := Num.FromStr(lon1,Num#DEC) lon2 := GPS.lon_mmmm lon2 := Num.FromStr(lon2,Num#DEC) ' ALTITUDE alt1 := GPS.altitude_1 alt1 := ( Num.FromStr(alt1, Num#DEC) ) * 100 alt2 := GPS.altitude_2 alt2 := Num.FromStr(alt2, Num#DEC) alt1 := alt1 + alt2 ' QUALITY qual := GPS.quality qual := Num.FromStr(qual, Num#DEC) ' SATELLITES VIEWED sv := GPS.satellites sv := Num.FromStr(sv, Num#DEC) ' HDOP hdop1 := GPS.hdop_1 hdop1 := Num.FromStr(hdop1, Num#DEC) hdop2 := GPS.hdop_2 hdop2 := Num.FromStr(hdop2, Num#DEC) hdop1 := ( hdop1 * 10 ) + hdop2 waitcnt(1_000_000_0 + cnt)Having said all that, I think Perry's fix to the code, which zeros the gps buffer before each read is the best solution. If the time goes to 000000 you've lost lock.
My housekeeping routine cycles through and checks if the GPS is still there :
PUB HouseKeeping ' Primary pervasive loop OSD_Header ' put unchanging / background text onscreen repeat SetVariables ' define the variables HUD ' paint the Heads Up Display DATA FreshGPS ' check that the GPS is updating waitcnt(4_000_0000 + cnt) ' housekeeping loop cycle time (~3x/sec) PUB FreshGPS ' This routine compares successive GPS time strings to insure the GPS has not ceased inputing into ' memory or become disconnected. Once data is deemed "fresh" the gps validity check can be used. ' Why? If the GPS ceases to input, the previous values stay in memory, including the "GPS valid" data. ' This method should be called from a housekeeping loop. ' This reuses the VALID Satellite Fix byte in the GPRMC sentence for status by adding a new value "X": ' A (Active) ' V (inValid) options. ' X (Data not available) <= our addition to the NMEA values. LastCNT := CNT ' Use the internal CNT ccounter to determine update eta NextCNT := LastCnt + 12_000_000 ' gps update eta should be in ~1 second if NextCnt > CNT ' check if the GPS should have updated by now, else skip Tnow := Num.FromStr(gps.time,Num#DEC) ' numberic if Tnow <> Tpast ' FRESH data is different from old data fresh := 0 ' reset freshness check counter to 0 longmove(@Tpast,@Tnow,1) ' move value in Tnow to Tpast for next run else ' STALE data fresh++ ' increment the freshness check counter if fresh > 4 ' What to do with Stale data? 4 is an arbitrary number of fails TOGGLE(27) ' FLASH when STALE gps.noGpsData ' set valid byte to XTo Perry's GPS_IO method, I added the following:
pub noGPSData GPRMCa.long := string("X")which changes the VALID byte to an X. NMEA standard values are A (Active) and V (inValid), but both of these assume the GPS is outputting something.
Lastly, I am considering adding the FreshData method to the GPS_IO method, but that means it would need the NUMBERS.spin added too. I am trying to keep is as simple as possible, so are there any suggestions yeah or nay?
thanks again!
Paul