Shop OBEX P1 Docs P2 Docs Learn Events
Data Freshness Test — Parallax Forums

Data Freshness Test

Paul_HPaul_H Posts: 85
edited 2008-03-17 22:58 in Propeller 1
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


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

  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-03-12 23:02
    Actually your problem comes from your compare, the inequality operator works on a single quantity, so it's comparing "1" to "1" which is the first digit of the hour, only when the hour switches from 9:59:59am to 10:00:00am, 7:59:59pm to 8:00:00pm and 11:59:59 to midnight would a difference be detected. You will need to construct a string compare function which tests every value, or the easier way would be to compare the least significant digit of seconds (ie Tpast[noparse][[/noparse] 5]·<> Tnow[noparse][[/noparse] 5] ), as long as the data update isn't 10 seconds from each other the difference will be detected.

    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

  • PerryPerry Posts: 253
    edited 2008-03-13 00:45
    Paul:

    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
  • pgbpsupgbpsu Posts: 460
    edited 2008-03-13 01:30
    Hi Paul-

    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
  • Paul_HPaul_H Posts: 85
    edited 2008-03-13 02:50
    @Paul B - Thank You! The least significant byte (the single seconds) is the one the check in this case, not the Tens-of-hours. I am a easily befuddled when it comes to strings/chars/numbers/etc so thanks for clearing the cobwebs. I'll try this in the morning.

    @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 smile.gif I'll post my progress tomorrow.
    Paul
  • Chuck RiceChuck Rice Posts: 210
    edited 2008-03-13 04:28
    .
    Perry said...
    Paul:

    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 actually ended up removing that longfill line, thinking
    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-

    .
  • pgbpsupgbpsu Posts: 460
    edited 2008-03-13 13:52
    Paul and 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.
  • Paul_HPaul_H Posts: 85
    edited 2008-03-17 22:58
    Thanks again for all the input. Instead of clearing the GPS memory locaton on the propeller, I have decided to mark/update the gps.valid byte to a new value. If the problem clears, then this will be overwritten with real data.

    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 X                        
                         
    
    
    




    To 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
Sign In or Register to comment.