A GPS disciplined clock
Dependencies: net lpc1768 crypto clock web log
gps/gps.c
- Committer:
- andrewboyson
- Date:
- 2018-01-31
- Revision:
- 1:1c4013b67497
- Parent:
- 0:67724a462d86
- Child:
- 4:108157115360
File content as of revision 1:1c4013b67497:
#include <stdint.h> #include <stdbool.h> #include <stdio.h> #include "log.h" #include "defs.h" #include "nmea.h" #include "sync.h" #include "timer.h" #include "led.h" #define GPS_ENABLE_MASK_0 (1UL << 24) #define GPS_FIX_MASK_0 (1UL << 23) #define GPS_PPS_MASK_0 (1UL << 17) #define CONFIDENCE_OK 60 #define MIN_MS_SINCE_PULSE 150 #define BUCKET_COUNT 20 uint32_t buckets[BUCKET_COUNT] = {0}; static int bucketEnumerateIndex = 0; void GpsBucketEnumerateStart() { bucketEnumerateIndex = 0; } bool GpsBucketEnumerate(int size, char *text) //returns false if there is no more information { if (bucketEnumerateIndex >= BUCKET_COUNT) return false; snprintf(text, size, "%d\r\n", buckets[bucketEnumerateIndex]); //snprintf always teminates with a null character after n-1 characters bucketEnumerateIndex++; return true; } static int confidence = 0; bool GpsStable = false; static time_t gpsTime = 0; static uint32_t msTimer; static volatile bool hadPulse; __irq void GpsPpsHandler() { LPC_GPIOINT->IO0IntClr = GPS_PPS_MASK_0; SyncPpsI(); hadPulse = true; } void pulseN(int ms) { int missed = (ms + 500) / 1000; int ppsOffset = ms % 1000; gpsTime += missed; if (ppsOffset != 999 && ppsOffset != 0) { LogTimeF("GPS %4d ms PPS interval is not 999 or 000 ms - sync disabled\r\n", ms); confidence = 0; } if (confidence == CONFIDENCE_OK) SyncPpsN(gpsTime); } void GpsNmeaTimeReceived(time_t nmeaTime, int nmeaMs) { //Ignore time messages if the module is not ready or has no fix if (!NmeaHaveFix) return; if (NmeaModuleReadiness != NMEA_READY) return; //Get the time of the message relative to the last pulse int ms = TimerSinceMs(msTimer); //Add time to bins to allow display of distribution int bucket = ms * BUCKET_COUNT / 1000; if (bucket < BUCKET_COUNT) buckets[bucket]++; //Check for non zero ms in NMEA if (nmeaMs) LogTimeF("GPS %4d ms NMEA time has non zero ms = %d\r\n", ms, nmeaMs); //Ignore time messages which have probably overflowed from a previous pulse if (ms < MIN_MS_SINCE_PULSE) { LogTimeF("GPS %4d ms NMEA time message ignored as received before %d ms\r\n", ms, MIN_MS_SINCE_PULSE); return; } //Handle the time message if (gpsTime == nmeaTime) { confidence++; if (confidence > CONFIDENCE_OK) confidence = CONFIDENCE_OK; } else { confidence = 0; if (gpsTime) LogTimeF("GPS %4d ms NMEA time differs by %+d seconds so corrected pps count - sync disabled\r\n", ms, nmeaTime - gpsTime); else LogTimeF("GPS %4d ms not set so setting pps count to NMEA time - sync disabled\r\n", ms, nmeaTime - gpsTime); gpsTime = nmeaTime; } } void GpsMain() { NmeaMain(); //Disable syncing until Nmea module is ready if (NmeaModuleReadiness != NMEA_READY) confidence = 0; //Handle the arrival of a pulse int ms = TimerSinceMs(msTimer); bool pulseIsStopped = ms > 1000; if (hadPulse) { msTimer = TimerNowCount(); pulseN(ms); hadPulse = false; pulseIsStopped = false; //This gets the signal 1 scan before the ms is reset } //Check pulses are arriving static bool pulseWasStopped = false; if ( pulseIsStopped) confidence = 0; if ( pulseIsStopped && !pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have stopped - sync disabled\r\n", ms); if (!pulseIsStopped && pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have started\r\n", ms); pulseWasStopped = pulseIsStopped; //Record any fix quality changes static bool lastHaveFix = false; if (!NmeaHaveFix) confidence = 0; if ( NmeaHaveFix && !lastHaveFix) LogTimeF("GPS %4d ms NMEA fix acquired\r\n", ms); if (!NmeaHaveFix && lastHaveFix) LogTimeF("GPS %4d ms NMEA fix lost - sync disabled\r\n", ms); lastHaveFix = NmeaHaveFix; //Settle time after disruption GpsStable = confidence == CONFIDENCE_OK; static bool lastStable = false; if ( GpsStable && !lastStable) LogTimeF("GPS %4d ms stable - sync enabled\r\n", ms); lastStable = GpsStable; } void GpsInit() { msTimer = TimerNowCount(); NmeaInit(); LPC_GPIO0->FIODIR |= GPS_ENABLE_MASK_0; //Set the enable pin direction to 1 == output LPC_GPIO0->FIOCLR = GPS_ENABLE_MASK_0; //Set the enable to low to reset the GPS while (TimerSinceMs(msTimer) < 10) __nop(); LPC_GPIO0->FIOSET = GPS_ENABLE_MASK_0; //Set the enable to high LPC_GPIOINT->IO0IntEnR |= GPS_PPS_MASK_0; //Set the PPS pin to be interrupt on rise NVIC->ISER[0] |= 1 << 21; //6.5.1 bit1 == Interrupt set enable for EINT3. It MUST be enabled even for GPIO interrupts - I checked. }