Allows for a GPS module to be connected to a serial port and exposes an easy to use API to get the GPS data. New feature, added Mbed/LPC17xx RTC synchronisation
Fork of MODGPS by
Diff: GPS.cpp
- Revision:
- 0:db98027c0bbb
- Child:
- 2:8aa059e7d8b1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GPS.cpp Mon Nov 15 20:11:16 2010 +0000 @@ -0,0 +1,149 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "GPS.h" + +GPS::GPS(PinName tx, PinName rx, const char *name) : Serial(tx, rx, name) +{ + switch(_uidx) { + case 1: _base = LPC_UART1; break; + case 2: _base = LPC_UART2; break; + case 3: _base = LPC_UART3; break; + default : _base = NULL; break; + } + + _pps = NULL; + _ppsInUse = false; + + if (_base != NULL) attach(this, &GPS::rx_irq); + + _second100 = new Ticker; + _second100->attach_us(this, &GPS::ticktock, GPS_TICKTOCK); +} + +void +GPS::ppsAttach(PinName irq, ppsEdgeType type) +{ + if (_pps != NULL) delete(_pps); + _pps = new InterruptIn(irq); + if (type == ppsRise) _pps->rise(this, &GPS::pps_irq); + else _pps->fall(this, &GPS::pps_irq); + _ppsInUse = true; +} + +void +GPS::ppsUnattach(void) +{ + if (_pps != NULL) delete(_pps); + _ppsInUse = false; +} + +double +GPS::latitude(void) +{ + double a, b; + do { a = thePlace.lat; b = thePlace.lat; } while (a != b); + return a; +} + +double +GPS::longitude(void) +{ + double a, b; + do { a = thePlace.lon; b = thePlace.lon; } while (a != b); + return a; +} + +double +GPS::altitude(void) +{ + double a, b; + do { a = thePlace.alt; b = thePlace.alt; } while (a != b); + return a; +} + +GPS_Geodetic * +GPS::geodetic(GPS_Geodetic *q) +{ + GPS_Geodetic a, b; + + if (q == NULL) q = new GPS_Geodetic; + + do { + memcpy(&a, &thePlace, sizeof(GPS_Geodetic)); + memcpy(&b, &thePlace, sizeof(GPS_Geodetic)); + } + while (memcmp(&a, &b, sizeof(GPS_Geodetic)) != 0); + + return q; +} + +void +GPS::ticktock(void) +{ + // Increment the time structure by 1/100th of a second. + ++theTime; + + // Test the serial queue. + if (process_required) { + char *s = buffer[active_buffer == 0 ? 1 : 0]; + if (!strncmp(s, "$GPRMC", 6)) { + theTime.nmea_rmc(s); + cb_rmc.call(); + if (!_ppsInUse) theTime.fractionalReset(); + } + else if (!strncmp(s, "$GPGGA", 6)) { + thePlace.nmea_gga(s); + cb_gga.call(); + } + process_required = false; + } +} + +void +GPS::pps_irq(void) +{ + theTime.fractionalReset(); + theTime++; // Increment the time/date by one second. + cb_pps.call(); +} + +void +GPS::rx_irq(void) +{ + uint32_t iir __attribute__((unused)); + char c; + + if (_base) { + iir = (uint32_t)*((char *)_base + GPS_IIR); + while((int)(*((char *)_base + GPS_LSR) & 0x1)) { + c = (char)(*((char *)_base + GPS_RBR) & 0xFF); + buffer[active_buffer][rx_buffer_in++] = c; + rx_buffer_in &= (GPS_BUFFER_LEN - 1); + if (c == '\n') { + active_buffer = active_buffer == 0 ? 1 : 0; + process_required = true; + rx_buffer_in = 0; + } + } + } +}