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
Dependents: SatGPS AntiTheftGPS FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM GPS-Lora ... more
Diff: GPS.h
- Revision:
- 0:db98027c0bbb
- Child:
- 1:6aec92e77ad2
diff -r 000000000000 -r db98027c0bbb GPS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GPS.h Mon Nov 15 20:11:16 2010 +0000 @@ -0,0 +1,631 @@ +/* + 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. +*/ + +#ifndef GPS_H +#define GPS_H + +#include "mbed.h" +#include "GPS_Time.h" +#include "GPS_Geodetic.h" + +#define GPS_RBR 0x00 +#define GPS_THR 0x00 +#define GPS_DLL 0x00 +#define GPS_IER 0x04 +#define GPS_DML 0x04 +#define GPS_IIR 0x08 +#define GPS_FCR 0x08 +#define GPS_LCR 0x0C +#define GPS_LSR 0x14 +#define GPS_SCR 0x1C +#define GPS_ACR 0x20 +#define GPS_ICR 0x24 +#define GPS_FDR 0x28 +#define GPS_TER 0x30 + +#define GPS_BUFFER_LEN 128 +#define GPS_TICKTOCK 10000 + +/** @defgroup API */ + +/** GPS module + * + * @see http://mbed.org/cookbook/MODGPS + * @see example1.cpp + * @see example2.cpp + * + * Example: + * @code + * #include "mbed.h" + * #include "GPS.h" + * + * DigitalOut led1(LED1); + * Serial pc(USBTX, USBRX); + * GPS gps(NC, p10); + * + * int main() { + * GPS_Time t; + * + * // Wait for the GPS NMEA data to become valid. + * while (!gps.isTimeValid()) { + * led1 = !led1; + * wait(1); + * } + * + * gps.timeNow(&t); + * + * pc.printf("The time/date is %02d:%02d:%02d %02d/%02d/%04d\r\n", + * t.hour, t.minute, t.second, t.day, t.month, t.year); + * + * // Wait until at least four satellites produce a position fix and a valid quality. + * while (gps.numOfSats() < 4 && gps.getGPSquality != 0) { + * led1 = !led1; + * wait(1); + * } + * + * pc.printf("Lat = %.4f Lon = %.4f Alt = %.1fkm\r\n", + * gps.latitude(), gps.longitude, gps.altitude()); + * + * // Make the LED go steady to indicate we have finished. + * led1 = 1; + * + * while(1) {} + * } + * @endcode + * + */ + +class GPS : Serial { +public: + + //! The PPS edge type to interrupt on. + enum ppsEdgeType { + ppsRise = 0, /*!< Use the rising edge (default). */ + ppsFall /*!< Use the falling edge. */ + }; + + //! A copy of the Serial parity enum + enum Parity { + None = 0 + , Odd + , Even + , Forced1 + , Forced0 + }; + + //! GPS constructor. + /** + * The GPS constructor is used to initialise the GPS object. + * + * @param tx Usually unused and set to NC + * @param rx The RX pin the GPS is connected to, p10, p14( OR p25), p27. + * @param name An option name for RPC usage. + */ + GPS(PinName tx, PinName rx, const char *name = NULL); + + //! Is the time reported by the GPS valid. + /** + * Method used to check the validity of the time the GPS module is reporting. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * if (gps.isTimeValid()) { + * // Time is valid :) + * } + * else { + * // Doh, time is not valid :( + * ) + * + * @endcode + * + * @ingroup API + * @return bool true if valid, false otherwise + */ + bool isTimeValid(void) { return theTime.status == 'V' ? false : true; } + + //! Is the positional fix reported by the GPS valid. + /** + * Method used to check the validity of the positional data. This method + * returns the GGA field, 0 is "bad, 1 is "ok", etc. See the NMEA GGA + * description for more details + * + * @return int 0 on no fix, 1... (see NMEA GGA for more details). + */ + int getGPSquality(void) { return thePlace.getGPSquality(); } + + //! How many satellites were used in the last fix. + /** + * Method returns the number of GPS satellites used on the last fix. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * int sats = gps.numOfSats(); + * + * @endcode + * + * @ingroup API + * @return int The number of satellites. + */ + int numOfSats(void) { return thePlace.numOfSats(); } + + //! What was the last reported latitude (in degrees) + /** + * Method returns a double in degrees, positive being North, negative being South. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * double latitude = gps.latitude(); + * + * @endcode + * + * @ingroup API + * @return double Degrees + */ + double latitude(void); + + //! What was the last reported longitude (in degrees) + /** + * Method returns a double in degrees, positive being East, negative being West. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * double logitude = gps.logitude(); + * + * @endcode + * + * @ingroup API + * @return double Degrees + */ + double longitude(void); + + //! What was the last reported altitude (in kilometers) + /** + * Method returns a double in kilometers. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * double altitude = gps.altitude(); + * + * @endcode + * + * @ingroup API + * @return double Kilometers + */ + double altitude(void); + + //! What was the last reported altitude/height (in kilometers) + /** + * @see altitude() + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * double height = gps.height(); + * + * @endcode + * + * Note, this is identical to altitude() + * @see altitude() + * + * @ingroup API + * @return double Kilometers + */ + double height(void) { return altitude(); } + + //! Get all three geodetic parameters together. + /** + * Pass a pointer to a GPS_Geodetic object and the current + * GPS data will be copied into it. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the data... + * GPS_Geodetic p; + * gps.geodetic(&p); + * printf("Latitude = %.4f", p.lat); + * printf("Longitude = %.4f", p.lon); + * printf("Altitude = %.4f", p.alt); + * + * @endcode + * + * @ingroup API + * @param g A GSP_Geodetic pointer to an existing GPS_Geodetic object. + * @return GPS_Geodetic * The pointer passed in. + */ + GPS_Geodetic *geodetic(GPS_Geodetic *g); + + //! Get all three geodetic parameters together. + /** + * Get all the geodetic data at once. For example:- + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the data... + * GPS_Geodetic *p = gps.geodetic(); + * printf("Latitude = %.4f", p->lat); + * delete(p); // then remember to delete the object to prevent memory leaks. + * + * @endcode + * + * @ingroup API + * @return GPS_Geodetic * A pointer to the data. + */ + GPS_Geodetic *geodetic(void) { return geodetic(NULL); } + + //! Take a snap shot of the current time. + /** + * Pass a pointer to a GPS_Time object to get a copy of the current + * time and date as reported by the GPS. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the data... + * GPS_Time t; + * gps.timeNow(&t); + * printf("Year = %d", t.year); + * + * @endcode + * + * @ingroup API + * @param n A GPS_Time * pointer to an existing GPS_Time object. + * @return GPS_Time * The pointer passed in. + */ + GPS_Time * timeNow(GPS_Time *n) { return theTime.timeNow(n); } + + //! Take a snap shot of the current time. + /** + * Pass a pointer to a GPS_Time object to get a copy of the current + * time and date as reported by the GPS. + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the data... + * GPS_Time *t = gps.timeNow(); + * printf("Year = %d", t->year); + * delete(t); // Avoid memory leaks. + * + * @endcode + * + * @ingroup API + * @return GPS_Time * The pointer passed in. + */ + GPS_Time * timeNow(void) { GPS_Time *n = new GPS_Time; return theTime.timeNow(n); } + + //! Return the curent day. + /** + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the Julain Day Number. + * double julianDayNumber = gps.julianDayNumber(); + * + * @endcode + * + * @ingroup API + * @return double The Julian Date as a double. + */ + double julianDayNumber(void) { return theTime.julian_day_number(); } + + //! Return the curent date/time as a Julian date + /** + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * // Then get the Julian Date. + * double julianDate = gps.julianDate(); + * + * @endcode + * + * @ingroup API + * @return double The Julian Date as a double. + */ + double julianDate(void) { return theTime.julian_date(); } + + //! Get the current sidereal degree angle. + /** + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * double sidereal = gps.siderealDegrees(); + * + * @endcode + * + * @ingroup API + * @return double Sidereal degree angle.. + */ + double siderealDegrees(void) { return theTime.siderealDegrees(&theTime, longitude()); } + + //! Get the current sidereal hour angle. + /** + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * double sidereal = gps.siderealHA(); + * + * @endcode + * + * @ingroup API + * @return double Sidereal degree angle.. + */ + double siderealHA(void) { return theTime.siderealHA(&theTime, longitude()); } + + //! Optionally, connect a 1PPS single to an Mbed pin. + /** + * Optional: If the GPS unit has a 1PPS output, use this to + * connect that to our internal ISR. Using the 1PPS increases + * the GPS_Time time accuracy from +/-0.25s to +/-0.001s + * + * @code + * // Assuming we have a GPS object previously created... + * GPS gps(NC, p9); + * + * gps.ppsAttach(p29); // default to GPS::ppsRise, rising edge. + * + * // Or... + * gps.ppsAttach(p29, GPS::ppsRise); // The default. + * + * // Or... + * gps.ppsAttach(p29, GPS::ppsFall); // If a falling edge. + * + * @endcode + * + * <b>Note</b>, before using this function you should attach an actual + * callback function using attach_pps() + * + * @see attach_pps() + * + * @ingroup API + * @param irq A PinName to attach + * @param type The type of edge, MAX7456::ppsRise OR MAX7456::ppsFall + */ + void ppsAttach(PinName irq, ppsEdgeType type = ppsRise); + + //! Remove any 1PPS signal previously attached. + void ppsUnattach(void); + + //! GPS serial receive interrupt handler. + void rx_irq(void); + + //! GPS pps interrupt handler. + void pps_irq(void); + + //! A pointer to the UART peripheral base address being used. + void *_base; + + //! The RX serial buffer. + char buffer[2][GPS_BUFFER_LEN]; + + //! The current "active" buffer, i.e. the buffer the ISR is writing to. + int active_buffer; + + //! The active buffer "in" pointer. + int rx_buffer_in; + + //! Boolean flag set when the "passive" buffer is full and needs processing. + bool process_required; + + //! 10ms Ticker callback. + void ticktock(void); + + //! Attach a user object/method callback function to the PPS signal + /** + * Attach a user callback object/method to call when the 1PPS signal activates. + * + * @code + * class FOO { + * public: + * void myCallback(void); + * }; + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_pps(foo, &FOO::myCallback); + * + * @endcode + * + * @ingroup API + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach_pps(T* tptr, void (T::*mptr)(void)) { cb_pps.attach(tptr, mptr); } + + //! Attach a user callback function to the PPS signal + /** + * Attach a user callback function pointer to call when the 1PPS signal activates. + * + * @code + * void myCallback(void) { ... } + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_pps(&myCallback); + * + * @endcode + * + * @ingroup API + * @param fptr Callback function pointer + */ + void attach_pps(void (*fptr)(void)) { cb_pps.attach(fptr); } + + //! A callback object for the 1PPS user API. + FunctionPointer cb_pps; + + //! Attach a user callback function to the NMEA RMC message processed signal. + /** + * Attach a user callback object/method to call when an NMEA RMC packet has been processed. + * + * @code + * class FOO { + * public: + * void myCallback(void); + * }; + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_rmc(foo, &FOO::myCallback); + * + * @endcode + * + * @ingroup API + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach_rmc(T* tptr, void (T::*mptr)(void)) { cb_rmc.attach(tptr, mptr); } + + //! Attach a user callback function to the NMEA RMC message processed signal. + /** + * Attach a user callback function pointer to call when an NMEA RMC packet has been processed. + * + * @code + * void myCallback(void) { ... } + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_rmc(&myCallback); + * + * @endcode + * + * @ingroup API + * @param fptr Callback function pointer. + */ + void attach_rmc(void (*fptr)(void)) { cb_rmc.attach(fptr); } + + //! A callback object for the NMEA RMS message processed signal user API. + FunctionPointer cb_rmc; + + //! Attach a user callback function to the NMEA GGA message processed signal. + /** + * Attach a user callback object/method to call when an NMEA GGA packet has been processed. + * + * @code + * class FOO { + * public: + * void myCallback(void); + * }; + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_gga(foo, &FOO::myCallback); + * + * @endcode + * + * @ingroup API + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach_gga(T* tptr, void (T::*mptr)(void)) { cb_gga.attach(tptr, mptr); } + + //! Attach a user callback function to the NMEA GGA message processed signal. + /** + * Attach a user callback function pointer to call when an NMEA GGA packet has been processed. + * + * @code + * void myCallback(void) { ... } + * + * GPS gps(NC, p9); + * Foo foo; + * + * gps.attach_gga(&myCallback); + * + * @endcode + * + * @ingroup API + * @param fptr Callback function pointer. + */ + void attach_gga(void (*fptr)(void)) { cb_gga.attach(fptr); } + + //! A callback object for the NMEA GGA message processed signal user API. + FunctionPointer cb_gga; + + //! Set the baud rate the GPS module is using. + /** + * Set the baud rate of the serial port + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.baud + * + * @ingroup API + * @param baudrate The baudrate to set. + */ + void baud(int baudrate) { Serial::baud(baudrate); } + + //! Set the serial port format the GPS module is using. + /** + * Set the transmission format used by the Serial port + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format + * + * @ingroup API + * @param bits - The number of bits in a word (5-8; default = 8) + * @param parity - The parity used (GPS::None, GPS::Odd, GPS::Even, GPS::Forced1, GPS::Forced0; default = GPS::None) + * @param stop_bits - The number of stop bits (1 or 2; default = 1) + */ + void format(int bits, Parity parity, int stop_bits) { Serial::format(bits, (Serial::Parity)parity, stop_bits); } + +protected: + + //! Flag set true when a GPS PPS has been attached to a pin. + bool _ppsInUse; + + //! An InterruptIn object to "trigger" on the PPS edge. + InterruptIn *_pps; + + //! A Ticker object called every 10ms. + Ticker *_second100; + + //! A GPS_Time object used to hold the last parsed time/date data. + GPS_Time theTime; + + //! A GPS_Geodetic object used to hold the last parsed positional data. + GPS_Geodetic thePlace; +}; + +#endif +