Graham Cantin / MODGPS

Dependents:   Telnet_server

Fork of MODGPS by Andy K

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GPS.h Source File

GPS.h

00001 /*
00002     Copyright (c) 2010 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021 */
00022 
00023 #ifndef GPS_H
00024 #define GPS_H
00025 
00026 #include "mbed.h"
00027 #include "GPS_Time.h"
00028 #include "GPS_Geodetic.h"
00029 
00030 #define GPS_RBR  0x00
00031 #define GPS_THR  0x00
00032 #define GPS_DLL  0x00
00033 #define GPS_IER  0x04
00034 #define GPS_DML  0x04
00035 #define GPS_IIR  0x08
00036 #define GPS_FCR  0x08
00037 #define GPS_LCR  0x0C
00038 #define GPS_LSR  0x14
00039 #define GPS_SCR  0x1C
00040 #define GPS_ACR  0x20
00041 #define GPS_ICR  0x24
00042 #define GPS_FDR  0x28
00043 #define GPS_TER  0x30
00044 
00045 #define GPS_BUFFER_LEN  128
00046 #define GPS_TICKTOCK    10000
00047 
00048 /** @defgroup API The MODGPS API */
00049 
00050 /** GPS module
00051  * @author Andy Kirkham
00052  * @see http://mbed.org/cookbook/MODGPS
00053  * @see example1.cpp
00054  * @see example2.cpp
00055  * @see API 
00056  *
00057  * @image html /media/uploads/AjK/gps_interfaces.png "Wiring up the GPS module"
00058  *
00059  * Example:
00060  * @code
00061  * #include "mbed.h"
00062  * #include "GPS.h"
00063  *
00064  * DigitalOut led1(LED1);
00065  * Serial pc(USBTX, USBRX);
00066  * GPS gps(NC, p10); 
00067  *
00068  * int main() {
00069  *     GPS_Time t;
00070  *
00071  *     // Wait for the GPS NMEA data to become valid.
00072  *     while (!gps.isTimeValid()) {
00073  *       led1 = !led1;
00074  *       wait(1);
00075  *     }
00076  *
00077  *     gps.timeNow(&t);
00078  *
00079  *     pc.printf("The time/date is %02d:%02d:%02d %02d/%02d/%04d\r\n",
00080  *        t.hour, t.minute, t.second, t.day, t.month, t.year);
00081  *
00082  *     // Wait until at least four satellites produce a position fix and a valid quality.
00083  *     while (gps.numOfSats() < 4 && gps.getGPSquality != 0) {
00084  *       led1 = !led1;
00085  *       wait(1);
00086  *     }
00087  *
00088  *     pc.printf("Lat = %.4f Lon = %.4f Alt = %.1fkm\r\n", 
00089  *         gps.latitude(), gps.longitude, gps.altitude());
00090  *
00091  *     // Make the LED go steady to indicate we have finished.
00092  *     led1 = 1;
00093  * 
00094  *     while(1) {}
00095  * }
00096  * @endcode
00097  */
00098 
00099 class GPS : Serial {
00100 public:
00101     
00102     //! The PPS edge type to interrupt on.
00103     enum ppsEdgeType { 
00104         ppsRise  = 0,    /*!< Use the rising edge (default). */
00105         ppsFall          /*!< Use the falling edge. */
00106     };
00107     
00108     //! A copy of the Serial parity enum
00109     enum Parity {
00110         None = 0
00111         , Odd
00112         , Even
00113         , Forced1   
00114         , Forced0
00115     };
00116     
00117     //! GPS constructor.
00118     /**
00119      * The GPS constructor is used to initialise the GPS object.
00120      *
00121      * @param tx Usually unused and set to NC
00122      * @param rx The RX pin the GPS is connected to, p10, p14( OR p25), p27.
00123      * @param name An option name for RPC usage.
00124      */
00125     GPS(PinName tx, PinName rx, const char *name = NULL);
00126 
00127     //! Is the time reported by the GPS valid.
00128     /**
00129      * Method used to check the validity of the time the GPS module is reporting.
00130      *
00131      * @code
00132      *     // Assuming we have a GPS object previously created...
00133      *     GPS gps(NC, p9); 
00134      *
00135      *     if (gps.isTimeValid()) {
00136      *         // Time is valid :)
00137      *     }
00138      *     else {
00139      *         // Doh, time is not valid :(
00140      *     )
00141      *     
00142      * @endcode
00143      *
00144      * @ingroup API
00145      * @return bool true if valid, false otherwise
00146      */
00147     bool isTimeValid(void) { return theTime.status == 'V' ? false : true; }
00148     
00149     //! Is the positional fix reported by the GPS valid.
00150     /**
00151      * Method used to check the validity of the positional data. This method
00152      * returns the GGA field, 0 is "bad, 1 is "ok", etc. See the NMEA GGA 
00153      * description for more details.
00154      *
00155      * @code
00156      *     // Assuming we have a GPS object previously created...
00157      *     GPS gps(NC, p9); 
00158      *
00159      *     if (gps.getGPSquality() == 0) {
00160      *         // The location fix is no good/not accurate :(
00161      *     }
00162      *     else {
00163      *         // All good, can use last fix data.
00164      *     )
00165      *     
00166      * @endcode
00167      *
00168      * @ingroup API
00169      * @return int 0 on no fix, 1... (see NMEA GGA for more details).
00170      */
00171     int getGPSquality(void) { return thePlace.getGPSquality(); }
00172     
00173     //! How many satellites were used in the last fix.
00174     /**
00175      * Method returns the number of GPS satellites used on the last fix.
00176      *
00177      * @code
00178      *     // Assuming we have a GPS object previously created...
00179      *     GPS gps(NC, p9); 
00180      *
00181      *     int sats = gps.numOfSats();
00182      *     
00183      * @endcode
00184      *
00185      * @ingroup API
00186      * @return int The number of satellites.
00187      */
00188     int numOfSats(void) { return thePlace.numOfSats(); }
00189     
00190     //! What was the last reported latitude (in degrees)
00191     /**
00192      * Method returns a double in degrees, positive being North, negative being South.
00193      *
00194      * @code
00195      *     // Assuming we have a GPS object previously created...
00196      *     GPS gps(NC, p9); 
00197      *
00198      *     double latitude = gps.latitude();
00199      *     
00200      * @endcode
00201      *
00202      * @ingroup API
00203      * @return double Degrees
00204      */
00205     double latitude(void);
00206     
00207     //! What was the last reported longitude (in degrees)
00208     /**
00209      * Method returns a double in degrees, positive being East, negative being West.
00210      *
00211      * @code
00212      *     // Assuming we have a GPS object previously created...
00213      *     GPS gps(NC, p9); 
00214      *
00215      *     double logitude = gps.logitude();
00216      *     
00217      * @endcode
00218      *
00219      * @ingroup API
00220      * @return double Degrees
00221      */
00222     double longitude(void);
00223     
00224     //! What was the last reported altitude (in kilometers)
00225     /**
00226      * Method returns a double in kilometers.
00227      *
00228      * @code
00229      *     // Assuming we have a GPS object previously created...
00230      *     GPS gps(NC, p9); 
00231      *
00232      *     double altitude = gps.altitude();
00233      *     
00234      * @endcode
00235      *
00236      * @ingroup API
00237      * @return double Kilometers
00238      */
00239     double altitude(void);
00240     
00241     //! What was the last reported altitude/height (in kilometers)
00242     /**
00243      * @see altitude()
00244      *
00245      * @code
00246      *     // Assuming we have a GPS object previously created...
00247      *     GPS gps(NC, p9); 
00248      *
00249      *     double height = gps.height();
00250      *     
00251      * @endcode
00252      *
00253      * Note, this is identical to altitude()
00254      * @see altitude()
00255      *
00256      * @ingroup API
00257      * @return double Kilometers
00258      */
00259     double height(void) { return altitude(); }
00260     
00261     //! Get all three geodetic parameters together.
00262     /**
00263      * Pass a pointer to a GPS_Geodetic object and the current
00264      * GPS data will be copied into it.
00265      *
00266      * @code
00267      *     // Assuming we have a GPS object previously created...
00268      *     GPS gps(NC, p9); 
00269      *
00270      *     // Then get the data...
00271      *     GPS_Geodetic p;
00272      *     gps.geodetic(&p);
00273      *     printf("Latitude  = %.4f", p.lat);
00274      *     printf("Longitude = %.4f", p.lon);
00275      *     printf("Altitude  = %.4f", p.alt);
00276      *
00277      * @endcode
00278      *
00279      * @ingroup API
00280      * @param g A GSP_Geodetic pointer to an existing GPS_Geodetic object.
00281      * @return GPS_Geodetic * The pointer passed in.
00282      */
00283     GPS_Geodetic *geodetic(GPS_Geodetic *g);
00284     
00285     //! Get all three geodetic parameters together.
00286     /**
00287      * Get all the geodetic data at once. For example:-
00288      *
00289      * @code
00290      *     // Assuming we have a GPS object previously created...
00291      *     GPS gps(NC, p9); 
00292      *
00293      *     // Then get the data...
00294      *     GPS_Geodetic *p = gps.geodetic();
00295      *     printf("Latitude = %.4f", p->lat);
00296      *     delete(p); // then remember to delete the object to prevent memory leaks.
00297      *
00298      * @endcode
00299      *
00300      * @ingroup API
00301      * @return GPS_Geodetic * A pointer to the data.
00302      */
00303     GPS_Geodetic *geodetic(void) { return geodetic(NULL); }
00304     
00305     //! Take a snap shot of the current time.
00306     /**
00307      * Pass a pointer to a GPS_Time object to get a copy of the current
00308      * time and date as reported by the GPS.
00309      *
00310      * @code
00311      *     // Assuming we have a GPS object previously created...
00312      *     GPS gps(NC, p9); 
00313      *
00314      *     // Then get the data...
00315      *     GPS_Time t;
00316      *     gps.timeNow(&t);
00317      *     printf("Year = %d", t.year);
00318      *
00319      * @endcode
00320      *
00321      * @ingroup API
00322      * @param n A GPS_Time * pointer to an existing GPS_Time object.
00323      * @return GPS_Time * The pointer passed in.
00324      */
00325     GPS_Time * timeNow(GPS_Time *n) { return theTime.timeNow(n); }
00326     
00327     //! Take a snap shot of the current time.
00328     /**
00329      * Pass a pointer to a GPS_Time object to get a copy of the current
00330      * time and date as reported by the GPS.
00331      *
00332      * @code
00333      *     // Assuming we have a GPS object previously created...
00334      *     GPS gps(NC, p9); 
00335      *
00336      *     // Then get the data...
00337      *     GPS_Time *t = gps.timeNow();
00338      *     printf("Year = %d", t->year);
00339      *     delete(t); // Avoid memory leaks.
00340      *
00341      * @endcode
00342      *
00343      * @ingroup API
00344      * @return GPS_Time * The pointer passed in.
00345      */
00346     GPS_Time * timeNow(void) { GPS_Time *n = new GPS_Time; return theTime.timeNow(n); }
00347     
00348     //! Return the curent day.
00349     /**
00350      * @code
00351      *     // Assuming we have a GPS object previously created...
00352      *     GPS gps(NC, p9); 
00353      *
00354      *     // Then get the Julain Day Number.
00355      *     double julianDayNumber = gps.julianDayNumber();
00356      *
00357      * @endcode
00358      *
00359      * @ingroup API
00360      * @return double The Julian Date as a double.
00361      */
00362     double julianDayNumber(void) { return theTime.julian_day_number(); } 
00363     
00364     //! Return the curent date/time as a Julian date
00365     /**
00366      * @code
00367      *     // Assuming we have a GPS object previously created...
00368      *     GPS gps(NC, p9); 
00369      *
00370      *     // Then get the Julian Date.
00371      *     double julianDate = gps.julianDate();
00372      *
00373      * @endcode
00374      *
00375      * @ingroup API
00376      * @return double The Julian Date as a double.
00377      */
00378     double julianDate(void) { return theTime.julian_date(); }
00379 
00380     //! Get the current sidereal degree angle.
00381     /**
00382      * @code
00383      *     // Assuming we have a GPS object previously created...
00384      *     GPS gps(NC, p9); 
00385      *     double sidereal = gps.siderealDegrees();
00386      *
00387      * @endcode
00388      *
00389      * @ingroup API
00390      * @return double Sidereal degree angle..
00391      */
00392     double siderealDegrees(void) { return theTime.siderealDegrees(&theTime, longitude()); }
00393     
00394     //! Get the current sidereal hour angle.
00395     /**
00396      * @code
00397      *     // Assuming we have a GPS object previously created...
00398      *     GPS gps(NC, p9); 
00399      *     double sidereal = gps.siderealHA();
00400      *
00401      * @endcode
00402      *
00403      * @ingroup API
00404      * @return double Sidereal degree angle..
00405      */
00406     double siderealHA(void) { return theTime.siderealHA(&theTime, longitude()); }
00407     
00408     //! Optionally, connect a 1PPS single to an Mbed pin.
00409     /**
00410      * Optional: If the GPS unit has a 1PPS output, use this to
00411      * connect that to our internal ISR. Using the 1PPS increases
00412      * the GPS_Time time accuracy from +/-0.25s to +/-0.001s
00413      *
00414      * @code
00415      *     // Assuming we have a GPS object previously created...
00416      *     GPS gps(NC, p9); 
00417      *
00418      *     gps.ppsAttach(p29); // default to GPS::ppsRise, rising edge. 
00419      *
00420      *     // Or...
00421      *     gps.ppsAttach(p29, GPS::ppsRise); // The default.
00422      *
00423      *     // Or...
00424      *     gps.ppsAttach(p29, GPS::ppsFall); // If a falling edge.
00425      *
00426      * @endcode
00427      *
00428      * <b>Note</b>, before using this function you should attach an actual
00429      * callback function using attach_pps()
00430      *
00431      * @see attach_pps()
00432      *
00433      * @ingroup API
00434      * @param irq A PinName to attach
00435      * @param type The type of edge, MAX7456::ppsRise OR MAX7456::ppsFall
00436      */
00437     void ppsAttach(PinName irq, ppsEdgeType type = ppsRise );
00438     
00439     //! Remove any 1PPS signal previously attached.
00440     void ppsUnattach(void);
00441     
00442     //! GPS serial receive interrupt handler.
00443     void rx_irq(void);    
00444     
00445     //! GPS pps interrupt handler.
00446     void pps_irq(void);
00447     
00448     //! A pointer to the UART peripheral base address being used.
00449     void *_base;
00450     
00451     //! The RX serial buffer.
00452     char buffer[2][GPS_BUFFER_LEN];
00453     
00454     //! The current "active" buffer, i.e. the buffer the ISR is writing to.
00455     int  active_buffer;
00456     
00457     //! The active buffer "in" pointer.
00458     int  rx_buffer_in;
00459     
00460     //! Boolean flag set when the "passive" buffer is full and needs processing.
00461     bool process_required;
00462     
00463     //! 10ms Ticker callback.
00464     void ticktock(void);
00465     
00466     //! Attach a user object/method callback function to the PPS signal
00467     /**
00468      * Attach a user callback object/method to call when the 1PPS signal activates. 
00469      *
00470      * @code
00471      *     class FOO {
00472      *     public:
00473      *         void myCallback(void);
00474      *     };
00475      *
00476      *     GPS gps(NC, p9); 
00477      *     Foo foo;
00478      *
00479      *     gps.attach_pps(foo, &FOO::myCallback);
00480      * 
00481      * @endcode
00482      *
00483      * @ingroup API
00484      * @param tptr pointer to the object to call the member function on
00485      * @param mptr pointer to the member function to be called
00486      */
00487     template<typename T>
00488     void attach_pps(T* tptr, void (T::*mptr)(void)) { cb_pps.attach(tptr, mptr); }
00489     
00490     //! Attach a user callback function to the PPS signal
00491     /**
00492      * Attach a user callback function pointer to call when the 1PPS signal activates. 
00493      *
00494      * @code
00495      *     void myCallback(void) { ... }
00496      *
00497      *     GPS gps(NC, p9); 
00498      *     Foo foo;
00499      *
00500      *     gps.attach_pps(&myCallback);
00501      * 
00502      * @endcode
00503      *
00504      * @ingroup API
00505      * @param fptr Callback function pointer
00506      */
00507     void attach_pps(void (*fptr)(void)) { cb_pps.attach(fptr); } 
00508     
00509     //! A callback object for the 1PPS user API.
00510     FunctionPointer cb_pps;
00511     
00512     //! Attach a user callback function to the NMEA RMC message processed signal.
00513     /**
00514      * Attach a user callback object/method to call when an NMEA RMC packet has been processed. 
00515      *
00516      * @code
00517      *     class FOO {
00518      *     public:
00519      *         void myCallback(void);
00520      *     };
00521      *
00522      *     GPS gps(NC, p9); 
00523      *     Foo foo;
00524      *
00525      *     gps.attach_rmc(foo, &FOO::myCallback);
00526      * 
00527      * @endcode
00528      *
00529      * @ingroup API 
00530      * @param tptr pointer to the object to call the member function on
00531      * @param mptr pointer to the member function to be called
00532      */
00533     template<typename T>
00534     void attach_rmc(T* tptr, void (T::*mptr)(void)) { cb_rmc.attach(tptr, mptr); }
00535     
00536     //! Attach a user callback function to the NMEA RMC message processed signal.
00537     /**
00538      * Attach a user callback function pointer to call when an NMEA RMC packet has been processed. 
00539      *
00540      * @code
00541      *     void myCallback(void) { ... }
00542      *
00543      *     GPS gps(NC, p9); 
00544      *     Foo foo;
00545      *
00546      *     gps.attach_rmc(&myCallback);
00547      * 
00548      * @endcode
00549      *
00550      * @ingroup API 
00551      * @param fptr Callback function pointer.
00552      */
00553     void attach_rmc(void (*fptr)(void)) { cb_rmc.attach(fptr); } 
00554     
00555     //! A callback object for the NMEA RMS message processed signal user API.
00556     FunctionPointer cb_rmc;
00557     
00558     //! Attach a user callback function to the NMEA GGA message processed signal.
00559     /**
00560      * Attach a user callback object/method to call when an NMEA GGA packet has been processed. 
00561      *
00562      * @code
00563      *     class FOO {
00564      *     public:
00565      *         void myCallback(void);
00566      *     };
00567      *
00568      *     GPS gps(NC, p9); 
00569      *     Foo foo;
00570      *
00571      *     gps.attach_gga(foo, &FOO::myCallback);
00572      * 
00573      * @endcode
00574      *
00575      * @ingroup API 
00576      * @param tptr pointer to the object to call the member function on
00577      * @param mptr pointer to the member function to be called
00578      */
00579     template<typename T>
00580     void attach_gga(T* tptr, void (T::*mptr)(void)) { cb_gga.attach(tptr, mptr); }
00581     
00582     //! Attach a user callback function to the NMEA GGA message processed signal.
00583     /**
00584      * Attach a user callback function pointer to call when an NMEA GGA packet has been processed. 
00585      *
00586      * @code
00587      *     void myCallback(void) { ... }
00588      *
00589      *     GPS gps(NC, p9); 
00590      *     Foo foo;
00591      *
00592      *     gps.attach_gga(&myCallback);
00593      * 
00594      * @endcode
00595      *
00596      * @ingroup API 
00597      * @param fptr Callback function pointer.
00598      */
00599     void attach_gga(void (*fptr)(void)) { cb_gga.attach(fptr); } 
00600     
00601     //! A callback object for the NMEA GGA message processed signal user API.
00602     FunctionPointer cb_gga;
00603 
00604     //! Set the baud rate the GPS module is using.
00605     /** 
00606      * Set the baud rate of the serial port
00607      * 
00608      * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.baud
00609      *
00610      * @ingroup API 
00611      * @param baudrate The baudrate to set.
00612      */
00613     void baud(int baudrate) { Serial::baud(baudrate); }
00614     
00615     //! Set the serial port format the GPS module is using. 
00616    /**
00617     * Set the transmission format used by the Serial port
00618     *
00619     * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format
00620     *
00621     * @ingroup API 
00622     * @param bits - The number of bits in a word (5-8; default = 8)
00623     * @param parity - The parity used (GPS::None, GPS::Odd, GPS::Even, GPS::Forced1, GPS::Forced0; default = GPS::None)
00624     * @param stop_bits - The number of stop bits (1 or 2; default = 1)
00625     */
00626     void format(int bits, Parity parity, int stop_bits) { Serial::format(bits, (Serial::Parity)parity, stop_bits); }
00627     
00628 protected:
00629 
00630     //! Flag set true when a GPS PPS has been attached to a pin.
00631     bool         _ppsInUse;
00632     
00633     //! An InterruptIn object to "trigger" on the PPS edge.
00634     InterruptIn *_pps;
00635     
00636     //! A Ticker object called every 10ms.
00637     Ticker      *_second100;
00638     
00639     //! A GPS_Time object used to hold the last parsed time/date data.
00640     GPS_Time     theTime;
00641     
00642     //! A GPS_Geodetic object used to hold the last parsed positional data.
00643     GPS_Geodetic thePlace;        
00644 };
00645 
00646 #endif
00647