A GPS disciplined clock
Dependencies: net lpc1768 crypto clock web log
gps/gps.c@0:67724a462d86, 2018-01-28 (annotated)
- Committer:
- andrewboyson
- Date:
- Sun Jan 28 14:41:59 2018 +0000
- Revision:
- 0:67724a462d86
- Child:
- 1:1c4013b67497
Updated libraries
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:67724a462d86 | 1 | #include <stdint.h> |
andrewboyson | 0:67724a462d86 | 2 | #include <stdbool.h> |
andrewboyson | 0:67724a462d86 | 3 | #include <stdio.h> |
andrewboyson | 0:67724a462d86 | 4 | |
andrewboyson | 0:67724a462d86 | 5 | #include "log.h" |
andrewboyson | 0:67724a462d86 | 6 | #include "defs.h" |
andrewboyson | 0:67724a462d86 | 7 | #include "nmea.h" |
andrewboyson | 0:67724a462d86 | 8 | #include "sync.h" |
andrewboyson | 0:67724a462d86 | 9 | #include "timer.h" |
andrewboyson | 0:67724a462d86 | 10 | #include "led.h" |
andrewboyson | 0:67724a462d86 | 11 | |
andrewboyson | 0:67724a462d86 | 12 | #define GPS_ENABLE_MASK_0 (1UL << 24) |
andrewboyson | 0:67724a462d86 | 13 | #define GPS_FIX_MASK_0 (1UL << 23) |
andrewboyson | 0:67724a462d86 | 14 | #define GPS_PPS_MASK_0 (1UL << 17) |
andrewboyson | 0:67724a462d86 | 15 | |
andrewboyson | 0:67724a462d86 | 16 | #define CONFIDENCE_OK 60 |
andrewboyson | 0:67724a462d86 | 17 | #define MIN_MS_SINCE_PULSE 150 |
andrewboyson | 0:67724a462d86 | 18 | |
andrewboyson | 0:67724a462d86 | 19 | #define BUCKET_COUNT 20 |
andrewboyson | 0:67724a462d86 | 20 | uint32_t buckets[BUCKET_COUNT] = {0}; |
andrewboyson | 0:67724a462d86 | 21 | |
andrewboyson | 0:67724a462d86 | 22 | void GpsBucketsAsString(int size, char *text) |
andrewboyson | 0:67724a462d86 | 23 | { |
andrewboyson | 0:67724a462d86 | 24 | char* p = text; |
andrewboyson | 0:67724a462d86 | 25 | for (int i = 0; i < BUCKET_COUNT; i++) |
andrewboyson | 0:67724a462d86 | 26 | { |
andrewboyson | 0:67724a462d86 | 27 | if (p - text < size - 20) |
andrewboyson | 0:67724a462d86 | 28 | { |
andrewboyson | 0:67724a462d86 | 29 | p += sprintf(p, "%d\r\n", buckets[i]); |
andrewboyson | 0:67724a462d86 | 30 | } |
andrewboyson | 0:67724a462d86 | 31 | } |
andrewboyson | 0:67724a462d86 | 32 | *p = 0; |
andrewboyson | 0:67724a462d86 | 33 | } |
andrewboyson | 0:67724a462d86 | 34 | |
andrewboyson | 0:67724a462d86 | 35 | |
andrewboyson | 0:67724a462d86 | 36 | static int confidence = 0; |
andrewboyson | 0:67724a462d86 | 37 | bool GpsStable = false; |
andrewboyson | 0:67724a462d86 | 38 | static time_t gpsTime = 0; |
andrewboyson | 0:67724a462d86 | 39 | static uint32_t msTimer; |
andrewboyson | 0:67724a462d86 | 40 | static volatile bool hadPulse; |
andrewboyson | 0:67724a462d86 | 41 | |
andrewboyson | 0:67724a462d86 | 42 | __irq void GpsPpsHandler() |
andrewboyson | 0:67724a462d86 | 43 | { |
andrewboyson | 0:67724a462d86 | 44 | LPC_GPIOINT->IO0IntClr = GPS_PPS_MASK_0; |
andrewboyson | 0:67724a462d86 | 45 | SyncPpsI(); |
andrewboyson | 0:67724a462d86 | 46 | hadPulse = true; |
andrewboyson | 0:67724a462d86 | 47 | } |
andrewboyson | 0:67724a462d86 | 48 | |
andrewboyson | 0:67724a462d86 | 49 | void pulseN(int ms) |
andrewboyson | 0:67724a462d86 | 50 | { |
andrewboyson | 0:67724a462d86 | 51 | int missed = (ms + 500) / 1000; |
andrewboyson | 0:67724a462d86 | 52 | int ppsOffset = ms % 1000; |
andrewboyson | 0:67724a462d86 | 53 | |
andrewboyson | 0:67724a462d86 | 54 | gpsTime += missed; |
andrewboyson | 0:67724a462d86 | 55 | |
andrewboyson | 0:67724a462d86 | 56 | if (ppsOffset != 999 && ppsOffset != 0) |
andrewboyson | 0:67724a462d86 | 57 | { |
andrewboyson | 0:67724a462d86 | 58 | LogTimeF("GPS %4d ms PPS interval is not 999 or 000 ms - sync disabled\r\n", ms); |
andrewboyson | 0:67724a462d86 | 59 | confidence = 0; |
andrewboyson | 0:67724a462d86 | 60 | } |
andrewboyson | 0:67724a462d86 | 61 | |
andrewboyson | 0:67724a462d86 | 62 | if (confidence == CONFIDENCE_OK) SyncPpsN(gpsTime); |
andrewboyson | 0:67724a462d86 | 63 | |
andrewboyson | 0:67724a462d86 | 64 | } |
andrewboyson | 0:67724a462d86 | 65 | void GpsNmeaTimeReceived(time_t nmeaTime, int nmeaMs) |
andrewboyson | 0:67724a462d86 | 66 | { |
andrewboyson | 0:67724a462d86 | 67 | //Ignore time messages if the module is not ready or has no fix |
andrewboyson | 0:67724a462d86 | 68 | if (!NmeaHaveFix) return; |
andrewboyson | 0:67724a462d86 | 69 | if (NmeaModuleReadiness != NMEA_READY) return; |
andrewboyson | 0:67724a462d86 | 70 | |
andrewboyson | 0:67724a462d86 | 71 | //Get the time of the message relative to the last pulse |
andrewboyson | 0:67724a462d86 | 72 | int ms = TimerSinceMs(msTimer); |
andrewboyson | 0:67724a462d86 | 73 | |
andrewboyson | 0:67724a462d86 | 74 | //Add time to bins to allow display of distribution |
andrewboyson | 0:67724a462d86 | 75 | int bucket = ms * BUCKET_COUNT / 1000; |
andrewboyson | 0:67724a462d86 | 76 | if (bucket < BUCKET_COUNT) buckets[bucket]++; |
andrewboyson | 0:67724a462d86 | 77 | |
andrewboyson | 0:67724a462d86 | 78 | //Check for non zero ms in NMEA |
andrewboyson | 0:67724a462d86 | 79 | if (nmeaMs) LogTimeF("GPS %4d ms NMEA time has non zero ms = %d\r\n", ms, nmeaMs); |
andrewboyson | 0:67724a462d86 | 80 | |
andrewboyson | 0:67724a462d86 | 81 | //Ignore time messages which have probably overflowed from a previous pulse |
andrewboyson | 0:67724a462d86 | 82 | if (ms < MIN_MS_SINCE_PULSE) |
andrewboyson | 0:67724a462d86 | 83 | { |
andrewboyson | 0:67724a462d86 | 84 | LogTimeF("GPS %4d ms NMEA time message ignored as received before %d ms\r\n", ms, MIN_MS_SINCE_PULSE); |
andrewboyson | 0:67724a462d86 | 85 | return; |
andrewboyson | 0:67724a462d86 | 86 | } |
andrewboyson | 0:67724a462d86 | 87 | |
andrewboyson | 0:67724a462d86 | 88 | //Handle the time message |
andrewboyson | 0:67724a462d86 | 89 | if (gpsTime == nmeaTime) |
andrewboyson | 0:67724a462d86 | 90 | { |
andrewboyson | 0:67724a462d86 | 91 | confidence++; |
andrewboyson | 0:67724a462d86 | 92 | if (confidence > CONFIDENCE_OK) confidence = CONFIDENCE_OK; |
andrewboyson | 0:67724a462d86 | 93 | } |
andrewboyson | 0:67724a462d86 | 94 | else |
andrewboyson | 0:67724a462d86 | 95 | { |
andrewboyson | 0:67724a462d86 | 96 | confidence = 0; |
andrewboyson | 0:67724a462d86 | 97 | if (gpsTime) LogTimeF("GPS %4d ms NMEA time differs by %+d seconds so corrected pps count - sync disabled\r\n", ms, nmeaTime - gpsTime); |
andrewboyson | 0:67724a462d86 | 98 | else LogTimeF("GPS %4d ms not set so setting pps count to NMEA time - sync disabled\r\n", ms, nmeaTime - gpsTime); |
andrewboyson | 0:67724a462d86 | 99 | gpsTime = nmeaTime; |
andrewboyson | 0:67724a462d86 | 100 | } |
andrewboyson | 0:67724a462d86 | 101 | } |
andrewboyson | 0:67724a462d86 | 102 | void GpsMain() |
andrewboyson | 0:67724a462d86 | 103 | { |
andrewboyson | 0:67724a462d86 | 104 | NmeaMain(); |
andrewboyson | 0:67724a462d86 | 105 | |
andrewboyson | 0:67724a462d86 | 106 | //Disable syncing until Nmea module is ready |
andrewboyson | 0:67724a462d86 | 107 | if (NmeaModuleReadiness != NMEA_READY) confidence = 0; |
andrewboyson | 0:67724a462d86 | 108 | |
andrewboyson | 0:67724a462d86 | 109 | //Handle the arrival of a pulse |
andrewboyson | 0:67724a462d86 | 110 | int ms = TimerSinceMs(msTimer); |
andrewboyson | 0:67724a462d86 | 111 | bool pulseIsStopped = ms > 1000; |
andrewboyson | 0:67724a462d86 | 112 | if (hadPulse) |
andrewboyson | 0:67724a462d86 | 113 | { |
andrewboyson | 0:67724a462d86 | 114 | msTimer = TimerNowCount(); |
andrewboyson | 0:67724a462d86 | 115 | pulseN(ms); |
andrewboyson | 0:67724a462d86 | 116 | hadPulse = false; |
andrewboyson | 0:67724a462d86 | 117 | pulseIsStopped = false; //This gets the signal 1 scan before the ms is reset |
andrewboyson | 0:67724a462d86 | 118 | } |
andrewboyson | 0:67724a462d86 | 119 | |
andrewboyson | 0:67724a462d86 | 120 | //Check pulses are arriving |
andrewboyson | 0:67724a462d86 | 121 | static bool pulseWasStopped = false; |
andrewboyson | 0:67724a462d86 | 122 | if ( pulseIsStopped) confidence = 0; |
andrewboyson | 0:67724a462d86 | 123 | if ( pulseIsStopped && !pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have stopped - sync disabled\r\n", ms); |
andrewboyson | 0:67724a462d86 | 124 | if (!pulseIsStopped && pulseWasStopped) LogTimeF("GPS %4d ms PPS pulses have started\r\n", ms); |
andrewboyson | 0:67724a462d86 | 125 | pulseWasStopped = pulseIsStopped; |
andrewboyson | 0:67724a462d86 | 126 | |
andrewboyson | 0:67724a462d86 | 127 | |
andrewboyson | 0:67724a462d86 | 128 | //Record any fix quality changes |
andrewboyson | 0:67724a462d86 | 129 | static bool lastHaveFix = false; |
andrewboyson | 0:67724a462d86 | 130 | if (!NmeaHaveFix) confidence = 0; |
andrewboyson | 0:67724a462d86 | 131 | if ( NmeaHaveFix && !lastHaveFix) LogTimeF("GPS %4d ms NMEA fix acquired\r\n", ms); |
andrewboyson | 0:67724a462d86 | 132 | if (!NmeaHaveFix && lastHaveFix) LogTimeF("GPS %4d ms NMEA fix lost - sync disabled\r\n", ms); |
andrewboyson | 0:67724a462d86 | 133 | lastHaveFix = NmeaHaveFix; |
andrewboyson | 0:67724a462d86 | 134 | |
andrewboyson | 0:67724a462d86 | 135 | //Settle time after disruption |
andrewboyson | 0:67724a462d86 | 136 | GpsStable = confidence == CONFIDENCE_OK; |
andrewboyson | 0:67724a462d86 | 137 | static bool lastStable = false; |
andrewboyson | 0:67724a462d86 | 138 | if ( GpsStable && !lastStable) LogTimeF("GPS %4d ms stable - sync enabled\r\n", ms); |
andrewboyson | 0:67724a462d86 | 139 | lastStable = GpsStable; |
andrewboyson | 0:67724a462d86 | 140 | } |
andrewboyson | 0:67724a462d86 | 141 | void GpsInit() |
andrewboyson | 0:67724a462d86 | 142 | { |
andrewboyson | 0:67724a462d86 | 143 | msTimer = TimerNowCount(); |
andrewboyson | 0:67724a462d86 | 144 | NmeaInit(); |
andrewboyson | 0:67724a462d86 | 145 | |
andrewboyson | 0:67724a462d86 | 146 | LPC_GPIO0->FIODIR |= GPS_ENABLE_MASK_0; //Set the enable pin direction to 1 == output |
andrewboyson | 0:67724a462d86 | 147 | LPC_GPIO0->FIOCLR = GPS_ENABLE_MASK_0; //Set the enable to low to reset the GPS |
andrewboyson | 0:67724a462d86 | 148 | while (TimerSinceMs(msTimer) < 10) __nop(); |
andrewboyson | 0:67724a462d86 | 149 | LPC_GPIO0->FIOSET = GPS_ENABLE_MASK_0; //Set the enable to high |
andrewboyson | 0:67724a462d86 | 150 | |
andrewboyson | 0:67724a462d86 | 151 | LPC_GPIOINT->IO0IntEnR |= GPS_PPS_MASK_0; //Set the PPS pin to be interrupt on rise |
andrewboyson | 0:67724a462d86 | 152 | NVIC->ISER[0] |= 1 << 21; //6.5.1 bit1 == Interrupt set enable for EINT3. It MUST be enabled even for GPIO interrupts - I checked. |
andrewboyson | 0:67724a462d86 | 153 | } |