VFD modular clock firmware

Dependencies:   DipCortex-EEprom RTC flw mbed

Committer:
Backstr?m
Date:
Tue Feb 24 23:01:40 2015 +0900
Revision:
12:dfb422107412
Parent:
0:f6e68b4ce169
Added tag v1.0.2 for changeset 34b344fdec98

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Backstrom 0:f6e68b4ce169 1 /*
Backstrom 0:f6e68b4ce169 2 * GPS support for VFD Modular Clock
Backstrom 0:f6e68b4ce169 3 * (C) 2012 William B Phelps
Backstrom 0:f6e68b4ce169 4 *
Backstrom 0:f6e68b4ce169 5 * mbed Port (C) 2014 Akafugu Corporation
Backstrom 0:f6e68b4ce169 6 *
Backstrom 0:f6e68b4ce169 7 * This program is free software; you can redistribute it and/or modify it under the
Backstrom 0:f6e68b4ce169 8 * terms of the GNU General Public License as published by the Free Software
Backstrom 0:f6e68b4ce169 9 * Foundation; either version 2 of the License, or (at your option) any later
Backstrom 0:f6e68b4ce169 10 * version.
Backstrom 0:f6e68b4ce169 11 *
Backstrom 0:f6e68b4ce169 12 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
Backstrom 0:f6e68b4ce169 13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
Backstrom 0:f6e68b4ce169 14 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Backstrom 0:f6e68b4ce169 15 *
Backstrom 0:f6e68b4ce169 16 */
Backstrom 0:f6e68b4ce169 17
Backstrom 0:f6e68b4ce169 18 #include "global.h"
Backstrom 0:f6e68b4ce169 19 #include "gps.h"
Backstrom 0:f6e68b4ce169 20
Backstrom 0:f6e68b4ce169 21 #ifdef HAVE_GPS
Backstrom 0:f6e68b4ce169 22
Backstrom 0:f6e68b4ce169 23 //Serial gps(P1_13, P1_14);
Backstrom 0:f6e68b4ce169 24 Serial* gps;
Backstrom 0:f6e68b4ce169 25
Backstrom 0:f6e68b4ce169 26 bool g_gps_updating = false;
Backstrom 0:f6e68b4ce169 27 int g_gps_cks_errors = 0;
Backstrom 0:f6e68b4ce169 28 int g_gps_parse_errors = 0;
Backstrom 0:f6e68b4ce169 29 int g_gps_time_errors = 0;
Backstrom 0:f6e68b4ce169 30
Backstrom 0:f6e68b4ce169 31 unsigned long tGPSupdate;
Backstrom 0:f6e68b4ce169 32
Backstrom 0:f6e68b4ce169 33 // we double buffer: read into one line and leave one for the main program
Backstrom 0:f6e68b4ce169 34 //volatile char gpsBuffer1[GPSBUFFERSIZE];
Backstrom 0:f6e68b4ce169 35 //volatile char gpsBuffer2[GPSBUFFERSIZE];
Backstrom 0:f6e68b4ce169 36 volatile char* gpsBuffer1;
Backstrom 0:f6e68b4ce169 37 volatile char* gpsBuffer2;
Backstrom 0:f6e68b4ce169 38
Backstrom 0:f6e68b4ce169 39 // our index into filling the current line
Backstrom 0:f6e68b4ce169 40 volatile uint8_t gpsBufferPtr;
Backstrom 0:f6e68b4ce169 41 // pointers to the double buffers
Backstrom 0:f6e68b4ce169 42 volatile char *gpsNextBuffer;
Backstrom 0:f6e68b4ce169 43 volatile char *gpsLastBuffer;
Backstrom 0:f6e68b4ce169 44 volatile uint8_t gpsDataReady_;
Backstrom 0:f6e68b4ce169 45
Backstrom 0:f6e68b4ce169 46 time_t tLast = 0; // for checking GPS messages
Backstrom 0:f6e68b4ce169 47
Backstrom 0:f6e68b4ce169 48 void GPSread()
Backstrom 0:f6e68b4ce169 49 {
Backstrom 0:f6e68b4ce169 50 char c = gps->getc();
Backstrom 0:f6e68b4ce169 51
Backstrom 0:f6e68b4ce169 52 if (c == '$') {
Backstrom 0:f6e68b4ce169 53 gpsNextBuffer[gpsBufferPtr] = 0;
Backstrom 0:f6e68b4ce169 54 gpsBufferPtr = 0;
Backstrom 0:f6e68b4ce169 55 }
Backstrom 0:f6e68b4ce169 56 if (c == '\n') { // newline marks end of sentence
Backstrom 0:f6e68b4ce169 57 gpsNextBuffer[gpsBufferPtr] = 0; // terminate string
Backstrom 0:f6e68b4ce169 58 if (gpsNextBuffer == gpsBuffer1) { // switch buffers
Backstrom 0:f6e68b4ce169 59 gpsNextBuffer = gpsBuffer2;
Backstrom 0:f6e68b4ce169 60 gpsLastBuffer = gpsBuffer1;
Backstrom 0:f6e68b4ce169 61 } else {
Backstrom 0:f6e68b4ce169 62 gpsNextBuffer = gpsBuffer1;
Backstrom 0:f6e68b4ce169 63 gpsLastBuffer = gpsBuffer2;
Backstrom 0:f6e68b4ce169 64 }
Backstrom 0:f6e68b4ce169 65 gpsBufferPtr = 0;
Backstrom 0:f6e68b4ce169 66 gpsDataReady_ = true; // signal data ready
Backstrom 0:f6e68b4ce169 67 }
Backstrom 0:f6e68b4ce169 68
Backstrom 0:f6e68b4ce169 69 gpsNextBuffer[gpsBufferPtr++] = c; // add char to current buffer, then increment index
Backstrom 0:f6e68b4ce169 70 if (gpsBufferPtr >= GPSBUFFERSIZE) // if buffer full
Backstrom 0:f6e68b4ce169 71 gpsBufferPtr = GPSBUFFERSIZE-1; // decrement index to make room (overrun)
Backstrom 0:f6e68b4ce169 72 }
Backstrom 0:f6e68b4ce169 73
Backstrom 0:f6e68b4ce169 74 uint8_t gpsDataReady(void) {
Backstrom 0:f6e68b4ce169 75 return gpsDataReady_;
Backstrom 0:f6e68b4ce169 76 }
Backstrom 0:f6e68b4ce169 77
Backstrom 0:f6e68b4ce169 78 char *gpsNMEA(void) {
Backstrom 0:f6e68b4ce169 79 gpsDataReady_ = false;
Backstrom 0:f6e68b4ce169 80 return (char *)gpsLastBuffer;
Backstrom 0:f6e68b4ce169 81 }
Backstrom 0:f6e68b4ce169 82
Backstrom 0:f6e68b4ce169 83 uint32_t parsedecimal(char *str, uint8_t len) {
Backstrom 0:f6e68b4ce169 84 uint32_t d = 0;
Backstrom 0:f6e68b4ce169 85 for (uint8_t i=0; i<len; i++) {
Backstrom 0:f6e68b4ce169 86 if ((str[i] > '9') || (str[0] < '0'))
Backstrom 0:f6e68b4ce169 87 return d; // no more digits
Backstrom 0:f6e68b4ce169 88 d = (d*10) + (str[i] - '0');
Backstrom 0:f6e68b4ce169 89 }
Backstrom 0:f6e68b4ce169 90 return d;
Backstrom 0:f6e68b4ce169 91 }
Backstrom 0:f6e68b4ce169 92
Backstrom 0:f6e68b4ce169 93 int32_t _abs(int32_t a) {
Backstrom 0:f6e68b4ce169 94 if (a < 0) return -a;
Backstrom 0:f6e68b4ce169 95 return a;
Backstrom 0:f6e68b4ce169 96 }
Backstrom 0:f6e68b4ce169 97
Backstrom 0:f6e68b4ce169 98 const char hex[17] = "0123456789ABCDEF";
Backstrom 0:f6e68b4ce169 99
Backstrom 0:f6e68b4ce169 100 uint8_t atoh(char x) {
Backstrom 0:f6e68b4ce169 101 return (strchr(hex, x) - hex);
Backstrom 0:f6e68b4ce169 102 }
Backstrom 0:f6e68b4ce169 103
Backstrom 0:f6e68b4ce169 104 uint32_t hex2i(char *str, uint8_t len) {
Backstrom 0:f6e68b4ce169 105 uint32_t d = 0;
Backstrom 0:f6e68b4ce169 106 for (uint8_t i=0; i<len; i++) {
Backstrom 0:f6e68b4ce169 107 d = (d*10) + (strchr(hex, str[i]) - hex);
Backstrom 0:f6e68b4ce169 108 }
Backstrom 0:f6e68b4ce169 109 return d;
Backstrom 0:f6e68b4ce169 110 }
Backstrom 0:f6e68b4ce169 111
Backstrom 0:f6e68b4ce169 112 // find next token in GPS string - find next comma, then point to following char
Backstrom 0:f6e68b4ce169 113 char * ntok ( char *ptr ) {
Backstrom 0:f6e68b4ce169 114 ptr = strchr(ptr, ','); // Find the next comma
Backstrom 0:f6e68b4ce169 115 if (ptr == NULL) return NULL;
Backstrom 0:f6e68b4ce169 116 ptr++; // point at next char after comma
Backstrom 0:f6e68b4ce169 117 return ptr;
Backstrom 0:f6e68b4ce169 118 }
Backstrom 0:f6e68b4ce169 119
Backstrom 0:f6e68b4ce169 120 // 225446 Time of fix 22:54:46 UTC
Backstrom 0:f6e68b4ce169 121 // A Navigation receiver warning A = OK, V = warning
Backstrom 0:f6e68b4ce169 122 // 4916.45,N Latitude 49 deg. 16.45 min North
Backstrom 0:f6e68b4ce169 123 // 12311.12,W Longitude 123 deg. 11.12 min West
Backstrom 0:f6e68b4ce169 124 // 000.5 Speed over ground, Knots
Backstrom 0:f6e68b4ce169 125 // 054.7 Course Made Good, True
Backstrom 0:f6e68b4ce169 126 // 191194 Date of fix 19 November 1994
Backstrom 0:f6e68b4ce169 127 // 020.3,E Magnetic variation 20.3 deg East
Backstrom 0:f6e68b4ce169 128 // *68 mandatory checksum
Backstrom 0:f6e68b4ce169 129
Backstrom 0:f6e68b4ce169 130 //$GPRMC,225446.000,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68\r\n
Backstrom 0:f6e68b4ce169 131 // 0 1 2 3 4 5 6 7
Backstrom 0:f6e68b4ce169 132 // 0123456789012345678901234567890123456789012345678901234567890123456789012
Backstrom 0:f6e68b4ce169 133 // 0 1 2 3 4 5 6 7 8 9 10 11 12
Backstrom 0:f6e68b4ce169 134 time_t parseGPSdata(char *gpsBuffer, bool& error, bool& fix, int8_t tzh, uint8_t tzm) {
Backstrom 0:f6e68b4ce169 135 time_t tNow;
Backstrom 0:f6e68b4ce169 136 struct tm tm;
Backstrom 0:f6e68b4ce169 137 uint8_t gpsCheck1, gpsCheck2; // checksums
Backstrom 0:f6e68b4ce169 138
Backstrom 0:f6e68b4ce169 139 char gpsFixStat; // fix status
Backstrom 0:f6e68b4ce169 140 // char gpsLat[7]; // ddmm.ff (with decimal point)
Backstrom 0:f6e68b4ce169 141 // char gpsLatH; // hemisphere
Backstrom 0:f6e68b4ce169 142 // char gpsLong[8]; // dddmm.ff (with decimal point)
Backstrom 0:f6e68b4ce169 143 // char gpsLongH; // hemisphere
Backstrom 0:f6e68b4ce169 144 // char gpsSpeed[5]; // speed over ground
Backstrom 0:f6e68b4ce169 145 // char gpsCourse[5]; // Course
Backstrom 0:f6e68b4ce169 146 // char gpsDate[6]; // Date
Backstrom 0:f6e68b4ce169 147 // char gpsMagV[5]; // Magnetic variation
Backstrom 0:f6e68b4ce169 148 // char gpsMagD; // Mag var E/W
Backstrom 0:f6e68b4ce169 149 // char gpsCKS[2]; // Checksum without asterisk
Backstrom 0:f6e68b4ce169 150
Backstrom 0:f6e68b4ce169 151 error = false;
Backstrom 0:f6e68b4ce169 152 fix = false;
Backstrom 0:f6e68b4ce169 153
Backstrom 0:f6e68b4ce169 154 char *ptr;
Backstrom 0:f6e68b4ce169 155 uint32_t tmp;
Backstrom 0:f6e68b4ce169 156 if ( strncmp( gpsBuffer, "$GPRMC,", 7 ) == 0 ) {
Backstrom 0:f6e68b4ce169 157 //Calculate checksum from the received data
Backstrom 0:f6e68b4ce169 158 ptr = &gpsBuffer[1]; // start at the "G"
Backstrom 0:f6e68b4ce169 159 gpsCheck1 = 0; // init collector
Backstrom 0:f6e68b4ce169 160
Backstrom 0:f6e68b4ce169 161 // Loop through entire string, XORing each character to the next
Backstrom 0:f6e68b4ce169 162 while (*ptr != '*') // count all the bytes up to the asterisk
Backstrom 0:f6e68b4ce169 163 {
Backstrom 0:f6e68b4ce169 164 gpsCheck1 ^= *ptr;
Backstrom 0:f6e68b4ce169 165 ptr++;
Backstrom 0:f6e68b4ce169 166 if (ptr>(gpsBuffer+GPSBUFFERSIZE)) goto GPSerrorP; // extra sanity check, can't hurt...
Backstrom 0:f6e68b4ce169 167 }
Backstrom 0:f6e68b4ce169 168 // now get the checksum from the string itself, which is in hex
Backstrom 0:f6e68b4ce169 169 gpsCheck2 = atoh(*(ptr+1)) * 16 + atoh(*(ptr+2));
Backstrom 0:f6e68b4ce169 170
Backstrom 0:f6e68b4ce169 171 if (gpsCheck1 == gpsCheck2) { // if checksums match, process the data
Backstrom 0:f6e68b4ce169 172 ptr = &gpsBuffer[1]; // start at beginning of buffer
Backstrom 0:f6e68b4ce169 173 ptr = ntok(ptr); // Find the time string
Backstrom 0:f6e68b4ce169 174 if (ptr == NULL) goto GPSerrorP;
Backstrom 0:f6e68b4ce169 175 char *p2 = strchr(ptr, ','); // find comma after Time
Backstrom 0:f6e68b4ce169 176 if (p2 == NULL) goto GPSerrorP;
Backstrom 0:f6e68b4ce169 177 if (p2 < (ptr+6)) goto GPSerrorP; // Time must be at least 6 chars
Backstrom 0:f6e68b4ce169 178 tmp = parsedecimal(ptr, 6); // parse integer portion
Backstrom 0:f6e68b4ce169 179 tm.tm_hour = tmp / 10000;
Backstrom 0:f6e68b4ce169 180 tm.tm_min = (tmp / 100) % 100;
Backstrom 0:f6e68b4ce169 181 tm.tm_sec = tmp % 100;
Backstrom 0:f6e68b4ce169 182 ptr = ntok(ptr); // Find the next token - Status
Backstrom 0:f6e68b4ce169 183 if (ptr == NULL) goto GPSerrorP;
Backstrom 0:f6e68b4ce169 184 gpsFixStat = ptr[0];
Backstrom 0:f6e68b4ce169 185 if (gpsFixStat == 'A') { // if data valid, parse time & date
Backstrom 0:f6e68b4ce169 186 fix = true;
Backstrom 0:f6e68b4ce169 187
Backstrom 0:f6e68b4ce169 188 for (uint8_t n=0; n<7; n++) { // skip 6 tokend, find date
Backstrom 0:f6e68b4ce169 189 ptr = ntok(ptr); // Find the next token
Backstrom 0:f6e68b4ce169 190 if (ptr == NULL) goto GPSerrorP; // error if not found
Backstrom 0:f6e68b4ce169 191 }
Backstrom 0:f6e68b4ce169 192 p2 = strchr(ptr, ','); // find comma after Date
Backstrom 0:f6e68b4ce169 193 if (p2 == NULL) goto GPSerrorP;
Backstrom 0:f6e68b4ce169 194 if (p2 != (ptr+6)) goto GPSerrorP; // check date length
Backstrom 0:f6e68b4ce169 195 tmp = parsedecimal(ptr, 6);
Backstrom 0:f6e68b4ce169 196 tm.tm_mday = tmp / 10000;
Backstrom 0:f6e68b4ce169 197 tm.tm_mon = ((tmp / 100) % 100) - 1; // zero offset for month
Backstrom 0:f6e68b4ce169 198 tm.tm_year = tmp % 100;
Backstrom 0:f6e68b4ce169 199
Backstrom 0:f6e68b4ce169 200 ptr = strchr(ptr, '*'); // Find Checksum
Backstrom 0:f6e68b4ce169 201 if (ptr == NULL) goto GPSerrorP;
Backstrom 0:f6e68b4ce169 202
Backstrom 0:f6e68b4ce169 203 tm.tm_year = y2kYearToTm(tm.tm_year); // convert yy year to (yyyy-1900) (add 100)
Backstrom 0:f6e68b4ce169 204 tNow = mktime(&tm); // convert to time_t - seconds since 0/0/1970
Backstrom 0:f6e68b4ce169 205
Backstrom 0:f6e68b4ce169 206 // If time jumps by more than a minute, complain about it. Either poor GPS signal or an error in the data
Backstrom 0:f6e68b4ce169 207 if ( (tLast>0) && (_abs(tNow - tLast)>60) ) // Beep if over 60 seconds since last GPRMC?
Backstrom 0:f6e68b4ce169 208 {
Backstrom 0:f6e68b4ce169 209 goto GPSerrorT; // it's probably an error
Backstrom 0:f6e68b4ce169 210 }
Backstrom 0:f6e68b4ce169 211 else {
Backstrom 0:f6e68b4ce169 212 tLast = tNow;
Backstrom 0:f6e68b4ce169 213 tNow = tNow + (long)(tzh) * SECS_PER_HOUR + (long)tzm;
Backstrom 0:f6e68b4ce169 214
Backstrom 0:f6e68b4ce169 215 }
Backstrom 0:f6e68b4ce169 216 } // if fix status is A
Backstrom 0:f6e68b4ce169 217 } // if checksums match
Backstrom 0:f6e68b4ce169 218 else // checksums do not match
Backstrom 0:f6e68b4ce169 219 goto GPSerrorC;
Backstrom 0:f6e68b4ce169 220
Backstrom 0:f6e68b4ce169 221 return tNow;
Backstrom 0:f6e68b4ce169 222
Backstrom 0:f6e68b4ce169 223 GPSerrorC:
Backstrom 0:f6e68b4ce169 224 g_gps_cks_errors++; // increment error count
Backstrom 0:f6e68b4ce169 225 goto GPSerror2a;
Backstrom 0:f6e68b4ce169 226 GPSerrorP:
Backstrom 0:f6e68b4ce169 227 g_gps_parse_errors++; // increment error count
Backstrom 0:f6e68b4ce169 228 goto GPSerror2a;
Backstrom 0:f6e68b4ce169 229 GPSerrorT:
Backstrom 0:f6e68b4ce169 230 #ifdef HAVE_SERIAL_DEBUG
Backstrom 0:f6e68b4ce169 231 tDelta = tNow - tGPSupdate;
Backstrom 0:f6e68b4ce169 232 Serial.print("tNow="); Serial.print(tNow); Serial.print(", tLast="); Serial.print(tLast); Serial.print(", diff="); Serial.print(tNow-tLast);
Backstrom 0:f6e68b4ce169 233 Serial.print(", tDelta="); Serial.print(tDelta);
Backstrom 0:f6e68b4ce169 234 Serial.println(" ");
Backstrom 0:f6e68b4ce169 235 #endif
Backstrom 0:f6e68b4ce169 236 g_gps_time_errors++; // increment error count
Backstrom 0:f6e68b4ce169 237 tLast = tNow; // save new time
Backstrom 0:f6e68b4ce169 238
Backstrom 0:f6e68b4ce169 239 GPSerror2a:
Backstrom 0:f6e68b4ce169 240 strcpy(gpsBuffer, ""); // wipe GPS buffer
Backstrom 0:f6e68b4ce169 241 } // if "$GPRMC"
Backstrom 0:f6e68b4ce169 242
Backstrom 0:f6e68b4ce169 243 error = true;
Backstrom 0:f6e68b4ce169 244 return 0;
Backstrom 0:f6e68b4ce169 245 }
Backstrom 0:f6e68b4ce169 246
Backstrom 0:f6e68b4ce169 247 void gps_init() {
Backstrom 0:f6e68b4ce169 248 gps = new Serial(P1_13, P1_14);
Backstrom 0:f6e68b4ce169 249 gps->attach(&GPSread);
Backstrom 0:f6e68b4ce169 250
Backstrom 0:f6e68b4ce169 251 gpsBuffer1 = new char[GPSBUFFERSIZE];
Backstrom 0:f6e68b4ce169 252 gpsBuffer2 = new char[GPSBUFFERSIZE];
Backstrom 0:f6e68b4ce169 253
Backstrom 0:f6e68b4ce169 254 tGPSupdate = 0; // reset GPS last update time
Backstrom 0:f6e68b4ce169 255 gpsDataReady_ = false;
Backstrom 0:f6e68b4ce169 256 gpsBufferPtr = 0;
Backstrom 0:f6e68b4ce169 257 gpsNextBuffer = gpsBuffer1;
Backstrom 0:f6e68b4ce169 258 gpsLastBuffer = gpsBuffer2;
Backstrom 0:f6e68b4ce169 259 }
Backstrom 0:f6e68b4ce169 260
Backstrom 0:f6e68b4ce169 261 #endif // HAVE_GPS