Revised Embedded Artists' MTK3339 library to save all raw GPS messages and enable optional decoding of RMC message.
Fork of MTK3339 by
MTK3339.cpp@0:bd0fe2412980, 2013-11-07 (annotated)
- Committer:
- embeddedartists
- Date:
- Thu Nov 07 11:46:53 2013 +0000
- Revision:
- 0:bd0fe2412980
- Child:
- 1:3057ad6a5d4b
First release
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 0:bd0fe2412980 | 1 | |
embeddedartists | 0:bd0fe2412980 | 2 | #include "mbed.h" |
embeddedartists | 0:bd0fe2412980 | 3 | #include "MTK3339.h" |
embeddedartists | 0:bd0fe2412980 | 4 | |
embeddedartists | 0:bd0fe2412980 | 5 | |
embeddedartists | 0:bd0fe2412980 | 6 | MTK3339::MTK3339(PinName tx, PinName rx) : _serial(tx, rx) { |
embeddedartists | 0:bd0fe2412980 | 7 | _serial.baud(9600); |
embeddedartists | 0:bd0fe2412980 | 8 | |
embeddedartists | 0:bd0fe2412980 | 9 | _state = StateStart; |
embeddedartists | 0:bd0fe2412980 | 10 | _sentenceMask = 0; |
embeddedartists | 0:bd0fe2412980 | 11 | _availDataType = NmeaInvalid; |
embeddedartists | 0:bd0fe2412980 | 12 | memset(&gga, 0, sizeof(GgaType)); |
embeddedartists | 0:bd0fe2412980 | 13 | memset(&vtg, 0, sizeof(VtgType)); |
embeddedartists | 0:bd0fe2412980 | 14 | } |
embeddedartists | 0:bd0fe2412980 | 15 | |
embeddedartists | 0:bd0fe2412980 | 16 | void MTK3339::start(void (*fptr)(void), int mask) { |
embeddedartists | 0:bd0fe2412980 | 17 | if (fptr && mask) { |
embeddedartists | 0:bd0fe2412980 | 18 | _dataCallback.attach(fptr); |
embeddedartists | 0:bd0fe2412980 | 19 | _sentenceMask = mask; |
embeddedartists | 0:bd0fe2412980 | 20 | _serial.attach(this, &MTK3339::uartIrq, Serial::RxIrq); |
embeddedartists | 0:bd0fe2412980 | 21 | } |
embeddedartists | 0:bd0fe2412980 | 22 | } |
embeddedartists | 0:bd0fe2412980 | 23 | |
embeddedartists | 0:bd0fe2412980 | 24 | void MTK3339::stop() { |
embeddedartists | 0:bd0fe2412980 | 25 | _dataCallback.attach(NULL); |
embeddedartists | 0:bd0fe2412980 | 26 | _sentenceMask = 0; |
embeddedartists | 0:bd0fe2412980 | 27 | _serial.attach(NULL); |
embeddedartists | 0:bd0fe2412980 | 28 | } |
embeddedartists | 0:bd0fe2412980 | 29 | |
embeddedartists | 0:bd0fe2412980 | 30 | MTK3339::NmeaSentence MTK3339::getAvailableDataType() { |
embeddedartists | 0:bd0fe2412980 | 31 | return _availDataType; |
embeddedartists | 0:bd0fe2412980 | 32 | } |
embeddedartists | 0:bd0fe2412980 | 33 | |
embeddedartists | 0:bd0fe2412980 | 34 | double MTK3339::getLatitudeAsDegrees() { |
embeddedartists | 0:bd0fe2412980 | 35 | if(gga.fix == 0 || gga.nsIndicator == 0) return 0; |
embeddedartists | 0:bd0fe2412980 | 36 | |
embeddedartists | 0:bd0fe2412980 | 37 | double l = gga.latitude; |
embeddedartists | 0:bd0fe2412980 | 38 | char ns = gga.nsIndicator; |
embeddedartists | 0:bd0fe2412980 | 39 | |
embeddedartists | 0:bd0fe2412980 | 40 | // convert from ddmm.mmmm to degrees only |
embeddedartists | 0:bd0fe2412980 | 41 | // 60 minutes is 1 degree |
embeddedartists | 0:bd0fe2412980 | 42 | |
embeddedartists | 0:bd0fe2412980 | 43 | int deg = (int)(l / 100); |
embeddedartists | 0:bd0fe2412980 | 44 | l = (l - deg*100.0) / 60.0; |
embeddedartists | 0:bd0fe2412980 | 45 | l = deg + l; |
embeddedartists | 0:bd0fe2412980 | 46 | if (ns == 'S') l = -l; |
embeddedartists | 0:bd0fe2412980 | 47 | |
embeddedartists | 0:bd0fe2412980 | 48 | return l; |
embeddedartists | 0:bd0fe2412980 | 49 | } |
embeddedartists | 0:bd0fe2412980 | 50 | |
embeddedartists | 0:bd0fe2412980 | 51 | double MTK3339::getLongitudeAsDegrees() { |
embeddedartists | 0:bd0fe2412980 | 52 | if(gga.fix == 0 || gga.ewIndicator == 0) return 0; |
embeddedartists | 0:bd0fe2412980 | 53 | |
embeddedartists | 0:bd0fe2412980 | 54 | double l = gga.longitude; |
embeddedartists | 0:bd0fe2412980 | 55 | char ew = gga.ewIndicator; |
embeddedartists | 0:bd0fe2412980 | 56 | |
embeddedartists | 0:bd0fe2412980 | 57 | // convert from ddmm.mmmm to degrees only |
embeddedartists | 0:bd0fe2412980 | 58 | // 60 minutes is 1 degree |
embeddedartists | 0:bd0fe2412980 | 59 | |
embeddedartists | 0:bd0fe2412980 | 60 | int deg = (int)(l / 100); |
embeddedartists | 0:bd0fe2412980 | 61 | l = (l - deg*100) / 60; |
embeddedartists | 0:bd0fe2412980 | 62 | l = deg + l; |
embeddedartists | 0:bd0fe2412980 | 63 | if (ew == 'W') l = -l; |
embeddedartists | 0:bd0fe2412980 | 64 | |
embeddedartists | 0:bd0fe2412980 | 65 | return l; |
embeddedartists | 0:bd0fe2412980 | 66 | } |
embeddedartists | 0:bd0fe2412980 | 67 | |
embeddedartists | 0:bd0fe2412980 | 68 | void MTK3339::parseGGA(char* data, int dataLen) { |
embeddedartists | 0:bd0fe2412980 | 69 | //http://aprs.gids.nl/nmea/#gga |
embeddedartists | 0:bd0fe2412980 | 70 | |
embeddedartists | 0:bd0fe2412980 | 71 | double tm = 0; |
embeddedartists | 0:bd0fe2412980 | 72 | |
embeddedartists | 0:bd0fe2412980 | 73 | memset(&gga, 0, sizeof(GgaType)); |
embeddedartists | 0:bd0fe2412980 | 74 | |
embeddedartists | 0:bd0fe2412980 | 75 | char* p = data; |
embeddedartists | 0:bd0fe2412980 | 76 | int pos = 0; |
embeddedartists | 0:bd0fe2412980 | 77 | |
embeddedartists | 0:bd0fe2412980 | 78 | p = strchr(p, ','); |
embeddedartists | 0:bd0fe2412980 | 79 | while (p != NULL && *p != 0) { |
embeddedartists | 0:bd0fe2412980 | 80 | p++; |
embeddedartists | 0:bd0fe2412980 | 81 | |
embeddedartists | 0:bd0fe2412980 | 82 | switch(pos) { |
embeddedartists | 0:bd0fe2412980 | 83 | case 0: // time: hhmmss.sss |
embeddedartists | 0:bd0fe2412980 | 84 | tm = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 85 | gga.hours = (int)(tm / 10000); |
embeddedartists | 0:bd0fe2412980 | 86 | gga.minutes = ((int)tm % 10000) / 100; |
embeddedartists | 0:bd0fe2412980 | 87 | gga.seconds = ((int)tm % 100); |
embeddedartists | 0:bd0fe2412980 | 88 | gga.milliseconds = (int)(tm * 1000) % 1000; |
embeddedartists | 0:bd0fe2412980 | 89 | break; |
embeddedartists | 0:bd0fe2412980 | 90 | case 1: // latitude: ddmm.mmmm |
embeddedartists | 0:bd0fe2412980 | 91 | gga.latitude = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 92 | break; |
embeddedartists | 0:bd0fe2412980 | 93 | case 2: // N/S indicator (north or south) |
embeddedartists | 0:bd0fe2412980 | 94 | if (*p == 'N' || *p == 'S') { |
embeddedartists | 0:bd0fe2412980 | 95 | gga.nsIndicator = *p; |
embeddedartists | 0:bd0fe2412980 | 96 | } |
embeddedartists | 0:bd0fe2412980 | 97 | break; |
embeddedartists | 0:bd0fe2412980 | 98 | case 3: // longitude: dddmm.mmmm |
embeddedartists | 0:bd0fe2412980 | 99 | gga.longitude = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 100 | break; |
embeddedartists | 0:bd0fe2412980 | 101 | case 4: // E/W indicator (east or west) |
embeddedartists | 0:bd0fe2412980 | 102 | if (*p == 'E' || *p == 'W') { |
embeddedartists | 0:bd0fe2412980 | 103 | gga.ewIndicator = *p; |
embeddedartists | 0:bd0fe2412980 | 104 | } |
embeddedartists | 0:bd0fe2412980 | 105 | break; |
embeddedartists | 0:bd0fe2412980 | 106 | case 5: // position indicator (1=no fix, 2=GPS fix, 3=Differential) |
embeddedartists | 0:bd0fe2412980 | 107 | gga.fix = strtol(p, NULL, 10); |
embeddedartists | 0:bd0fe2412980 | 108 | break; |
embeddedartists | 0:bd0fe2412980 | 109 | case 6: // num satellites |
embeddedartists | 0:bd0fe2412980 | 110 | gga.satellites = strtol(p, NULL, 10); |
embeddedartists | 0:bd0fe2412980 | 111 | break; |
embeddedartists | 0:bd0fe2412980 | 112 | case 7: // hdop |
embeddedartists | 0:bd0fe2412980 | 113 | gga.hdop = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 114 | break; |
embeddedartists | 0:bd0fe2412980 | 115 | case 8: // altitude |
embeddedartists | 0:bd0fe2412980 | 116 | gga.altitude = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 117 | break; |
embeddedartists | 0:bd0fe2412980 | 118 | case 9: // units |
embeddedartists | 0:bd0fe2412980 | 119 | // ignore units |
embeddedartists | 0:bd0fe2412980 | 120 | break; |
embeddedartists | 0:bd0fe2412980 | 121 | case 10: // geoidal separation |
embeddedartists | 0:bd0fe2412980 | 122 | gga.geoidal = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 123 | break; |
embeddedartists | 0:bd0fe2412980 | 124 | } |
embeddedartists | 0:bd0fe2412980 | 125 | pos++; |
embeddedartists | 0:bd0fe2412980 | 126 | |
embeddedartists | 0:bd0fe2412980 | 127 | p = strchr(p, ','); |
embeddedartists | 0:bd0fe2412980 | 128 | } |
embeddedartists | 0:bd0fe2412980 | 129 | |
embeddedartists | 0:bd0fe2412980 | 130 | } |
embeddedartists | 0:bd0fe2412980 | 131 | |
embeddedartists | 0:bd0fe2412980 | 132 | void MTK3339::parseVTG(char* data, int dataLen) { |
embeddedartists | 0:bd0fe2412980 | 133 | |
embeddedartists | 0:bd0fe2412980 | 134 | |
embeddedartists | 0:bd0fe2412980 | 135 | char* p = data; |
embeddedartists | 0:bd0fe2412980 | 136 | int pos = 0; |
embeddedartists | 0:bd0fe2412980 | 137 | |
embeddedartists | 0:bd0fe2412980 | 138 | memset(&vtg, 0, sizeof(VtgType)); |
embeddedartists | 0:bd0fe2412980 | 139 | |
embeddedartists | 0:bd0fe2412980 | 140 | p = strchr(p, ','); |
embeddedartists | 0:bd0fe2412980 | 141 | while (p != NULL && *p != 0) { |
embeddedartists | 0:bd0fe2412980 | 142 | p++; |
embeddedartists | 0:bd0fe2412980 | 143 | |
embeddedartists | 0:bd0fe2412980 | 144 | switch(pos) { |
embeddedartists | 0:bd0fe2412980 | 145 | case 0: // course in degrees |
embeddedartists | 0:bd0fe2412980 | 146 | vtg.course = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 147 | break; |
embeddedartists | 0:bd0fe2412980 | 148 | case 1: // Reference (T) |
embeddedartists | 0:bd0fe2412980 | 149 | break; |
embeddedartists | 0:bd0fe2412980 | 150 | case 2: // course magnetic (need customization) |
embeddedartists | 0:bd0fe2412980 | 151 | break; |
embeddedartists | 0:bd0fe2412980 | 152 | case 3: // reference (M) |
embeddedartists | 0:bd0fe2412980 | 153 | break; |
embeddedartists | 0:bd0fe2412980 | 154 | case 4: // speed in knots |
embeddedartists | 0:bd0fe2412980 | 155 | vtg.speedKnots = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 156 | break; |
embeddedartists | 0:bd0fe2412980 | 157 | case 5: // units (N) |
embeddedartists | 0:bd0fe2412980 | 158 | break; |
embeddedartists | 0:bd0fe2412980 | 159 | case 6: // speed in Km/h |
embeddedartists | 0:bd0fe2412980 | 160 | vtg.speedKmHour = strtod(p, NULL); |
embeddedartists | 0:bd0fe2412980 | 161 | break; |
embeddedartists | 0:bd0fe2412980 | 162 | case 7: // units (K) |
embeddedartists | 0:bd0fe2412980 | 163 | break; |
embeddedartists | 0:bd0fe2412980 | 164 | case 8: // mode |
embeddedartists | 0:bd0fe2412980 | 165 | if (*p == 'A' || *p == 'D' || *p == 'E') { |
embeddedartists | 0:bd0fe2412980 | 166 | vtg.mode = *p; |
embeddedartists | 0:bd0fe2412980 | 167 | } |
embeddedartists | 0:bd0fe2412980 | 168 | |
embeddedartists | 0:bd0fe2412980 | 169 | break; |
embeddedartists | 0:bd0fe2412980 | 170 | |
embeddedartists | 0:bd0fe2412980 | 171 | } |
embeddedartists | 0:bd0fe2412980 | 172 | |
embeddedartists | 0:bd0fe2412980 | 173 | pos++; |
embeddedartists | 0:bd0fe2412980 | 174 | |
embeddedartists | 0:bd0fe2412980 | 175 | p = strchr(p, ','); |
embeddedartists | 0:bd0fe2412980 | 176 | } |
embeddedartists | 0:bd0fe2412980 | 177 | } |
embeddedartists | 0:bd0fe2412980 | 178 | |
embeddedartists | 0:bd0fe2412980 | 179 | |
embeddedartists | 0:bd0fe2412980 | 180 | void MTK3339::parseData(char* data, int len) { |
embeddedartists | 0:bd0fe2412980 | 181 | do { |
embeddedartists | 0:bd0fe2412980 | 182 | |
embeddedartists | 0:bd0fe2412980 | 183 | // verify checksum |
embeddedartists | 0:bd0fe2412980 | 184 | if (len < 3 || (len > 3 && data[len-3] != '*')) { |
embeddedartists | 0:bd0fe2412980 | 185 | // invalid data |
embeddedartists | 0:bd0fe2412980 | 186 | break; |
embeddedartists | 0:bd0fe2412980 | 187 | } |
embeddedartists | 0:bd0fe2412980 | 188 | int sum = strtol(&data[len-2], NULL, 16); |
embeddedartists | 0:bd0fe2412980 | 189 | for(int i = 1; i < len-3; i++) { |
embeddedartists | 0:bd0fe2412980 | 190 | sum ^= data[i]; |
embeddedartists | 0:bd0fe2412980 | 191 | } |
embeddedartists | 0:bd0fe2412980 | 192 | if (sum != 0) { |
embeddedartists | 0:bd0fe2412980 | 193 | // invalid checksum |
embeddedartists | 0:bd0fe2412980 | 194 | break; |
embeddedartists | 0:bd0fe2412980 | 195 | } |
embeddedartists | 0:bd0fe2412980 | 196 | |
embeddedartists | 0:bd0fe2412980 | 197 | |
embeddedartists | 0:bd0fe2412980 | 198 | if (strncmp("$GPGGA", data, 6) == 0 && (_sentenceMask & NmeaGga) != 0) { |
embeddedartists | 0:bd0fe2412980 | 199 | parseGGA(data, len); |
embeddedartists | 0:bd0fe2412980 | 200 | _availDataType = NmeaGga; |
embeddedartists | 0:bd0fe2412980 | 201 | _dataCallback.call(); |
embeddedartists | 0:bd0fe2412980 | 202 | _availDataType = NmeaInvalid; |
embeddedartists | 0:bd0fe2412980 | 203 | } |
embeddedartists | 0:bd0fe2412980 | 204 | else if (strncmp("$GPVTG", data, 6) == 0 && (_sentenceMask & NmeaVtg) != 0) { |
embeddedartists | 0:bd0fe2412980 | 205 | parseVTG(data, len); |
embeddedartists | 0:bd0fe2412980 | 206 | _availDataType = NmeaVtg; |
embeddedartists | 0:bd0fe2412980 | 207 | _dataCallback.call(); |
embeddedartists | 0:bd0fe2412980 | 208 | _availDataType = NmeaInvalid; |
embeddedartists | 0:bd0fe2412980 | 209 | } |
embeddedartists | 0:bd0fe2412980 | 210 | |
embeddedartists | 0:bd0fe2412980 | 211 | |
embeddedartists | 0:bd0fe2412980 | 212 | } while(0); |
embeddedartists | 0:bd0fe2412980 | 213 | } |
embeddedartists | 0:bd0fe2412980 | 214 | |
embeddedartists | 0:bd0fe2412980 | 215 | void MTK3339::uartIrq() { |
embeddedartists | 0:bd0fe2412980 | 216 | char d = 0; |
embeddedartists | 0:bd0fe2412980 | 217 | |
embeddedartists | 0:bd0fe2412980 | 218 | while(_serial.readable()) { |
embeddedartists | 0:bd0fe2412980 | 219 | d = _serial.getc(); |
embeddedartists | 0:bd0fe2412980 | 220 | |
embeddedartists | 0:bd0fe2412980 | 221 | switch(_state) { |
embeddedartists | 0:bd0fe2412980 | 222 | case StateStart: |
embeddedartists | 0:bd0fe2412980 | 223 | if (d == '$') { |
embeddedartists | 0:bd0fe2412980 | 224 | _buf[0] = '$'; |
embeddedartists | 0:bd0fe2412980 | 225 | _bufPos = 1; |
embeddedartists | 0:bd0fe2412980 | 226 | _state = StateData; |
embeddedartists | 0:bd0fe2412980 | 227 | } |
embeddedartists | 0:bd0fe2412980 | 228 | break; |
embeddedartists | 0:bd0fe2412980 | 229 | case StateData: |
embeddedartists | 0:bd0fe2412980 | 230 | if (_bufPos >= MTK3339_BUF_SZ) { |
embeddedartists | 0:bd0fe2412980 | 231 | // error |
embeddedartists | 0:bd0fe2412980 | 232 | _state = StateStart; |
embeddedartists | 0:bd0fe2412980 | 233 | } |
embeddedartists | 0:bd0fe2412980 | 234 | else if (d == '\r') { |
embeddedartists | 0:bd0fe2412980 | 235 | |
embeddedartists | 0:bd0fe2412980 | 236 | _buf[_bufPos] = 0; |
embeddedartists | 0:bd0fe2412980 | 237 | |
embeddedartists | 0:bd0fe2412980 | 238 | parseData(_buf, _bufPos); |
embeddedartists | 0:bd0fe2412980 | 239 | |
embeddedartists | 0:bd0fe2412980 | 240 | _state = StateStart; |
embeddedartists | 0:bd0fe2412980 | 241 | } |
embeddedartists | 0:bd0fe2412980 | 242 | else { |
embeddedartists | 0:bd0fe2412980 | 243 | _buf[_bufPos++] = d; |
embeddedartists | 0:bd0fe2412980 | 244 | } |
embeddedartists | 0:bd0fe2412980 | 245 | |
embeddedartists | 0:bd0fe2412980 | 246 | break; |
embeddedartists | 0:bd0fe2412980 | 247 | } |
embeddedartists | 0:bd0fe2412980 | 248 | } |
embeddedartists | 0:bd0fe2412980 | 249 | } |