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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GPS.cpp Source File

GPS.cpp

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 #include "GPS.h"
00024 
00025 GPS::GPS(PinName tx, PinName rx, const char *name) : Serial(tx, rx, name) 
00026 {
00027     _nmeaOnUart0 = false;
00028     
00029     _lastByte = 0;
00030     
00031     _gga = (char *)NULL;
00032     
00033     _rmc = (char *)NULL;
00034     
00035     _vtg = (char *)NULL;
00036     
00037     switch(_uidx) {
00038         case 1:   _base = LPC_UART1; break;
00039         case 2:   _base = LPC_UART2; break;
00040         case 3:   _base = LPC_UART3; break;
00041         default : _base = NULL;      break;
00042     }
00043     
00044     _pps = NULL;
00045     _ppsInUse = false;
00046     
00047     if (_base != NULL) attach(this, &GPS::rx_irq);
00048     
00049     _second100 = new Ticker;
00050     _second100->attach_us(this, &GPS::ticktock, GPS_TICKTOCK);
00051 }
00052 
00053 void 
00054 GPS::ppsAttach(PinName irq, ppsEdgeType type) 
00055 {
00056     if (_pps != NULL) delete(_pps);
00057     _pps = new InterruptIn(irq);
00058     if (type == ppsRise ) _pps->rise(this, &GPS::pps_irq);
00059     else _pps->fall(this, &GPS::pps_irq);
00060     _ppsInUse = true;     
00061 }
00062     
00063 void 
00064 GPS::ppsUnattach(void) 
00065 {
00066     if (_pps != NULL) delete(_pps);
00067     _ppsInUse = false;
00068 }
00069     
00070 double 
00071 GPS::latitude(void)  
00072 {
00073     double a, b;
00074     do { a = thePlace.lat; b = thePlace.lat; }  while (a != b);
00075     return a; 
00076 }
00077 
00078 double 
00079 GPS::longitude(void) 
00080 { 
00081     double a, b;
00082     do { a = thePlace.lon; b = thePlace.lon; } while (a != b);
00083     return a; 
00084 }
00085 
00086 double 
00087 GPS::altitude(void)  
00088 { 
00089     double a, b;
00090     do { a = thePlace.alt; b = thePlace.alt; } while (a != b);
00091     return a; 
00092 }
00093 
00094 GPS_Geodetic *
00095 GPS::geodetic(GPS_Geodetic *q)
00096 {
00097     GPS_Geodetic a;
00098     
00099     if (q == NULL) q = new GPS_Geodetic;
00100     
00101     do {
00102         memcpy(&a, &thePlace, sizeof(GPS_Geodetic));
00103         memcpy(q,  &thePlace, sizeof(GPS_Geodetic));
00104     }
00105     while (memcmp(&a, q, sizeof(GPS_Geodetic)) != 0);
00106     
00107     return q;
00108 }
00109 
00110 GPS_VTG *
00111 GPS::vtg(GPS_VTG *q)
00112 {
00113     GPS_VTG a;
00114     
00115     if (q == NULL) q = new GPS_VTG;
00116     
00117     do {
00118         memcpy(&a, &theVTG, sizeof(GPS_VTG));
00119         memcpy(q,  &theVTG, sizeof(GPS_VTG));
00120     }
00121     while (memcmp(&a, q, sizeof(GPS_VTG)) != 0);
00122     
00123     return q;
00124 }
00125 
00126 void
00127 GPS::ticktock(void)
00128 {
00129     int i;
00130     
00131     // Increment the time structure by 1/100th of a second.
00132     ++theTime; 
00133     
00134     // Test the serial queue.
00135     if (process_required) {
00136         char *s = buffer[active_buffer == 0 ? 1 : 0];
00137         if (!strncmp(s, "$GPRMC", 6)) {
00138             if (_rmc) {
00139                 for(i = 0; s[i] != '\n'; i++) {
00140                     _rmc[i] = s[i];
00141                 }
00142                 _rmc[i++] = '\n'; _rmc[i] = '\0';
00143             }
00144             theTime.nmea_rmc(s);
00145             cb_rmc.call();
00146             if (!_ppsInUse) theTime.fractionalReset();
00147         }
00148         else if (!strncmp(s, "$GPGGA", 6)) {
00149             if (_gga) {
00150                 for(int i = 0; s[i] != '\n'; i++) {
00151                     _gga[i] = s[i];
00152                 }
00153                 _gga[i++] = '\n'; _gga[i] = '\0';
00154             }            
00155             thePlace.nmea_gga(s);            
00156             cb_gga.call();
00157         }
00158         else if (!strncmp(s, "$GPVTG", 6)) {
00159             if (_vtg) {
00160                 for(int i = 0; s[i] != '\n'; i++) {
00161                     _vtg[i] = s[i];
00162                 }
00163                 _vtg[i++] = '\n'; _vtg[i] = '\0';
00164             }
00165             theVTG.nmea_vtg(s);            
00166             cb_vtg.call();
00167         }
00168         else {
00169             if (_ukn) {
00170                 for(int i = 0; s[i] != '\n'; i++) {
00171                     _ukn[i] = s[i];
00172                 }
00173                 _ukn[i++] = '\n'; _ukn[i] = '\0';
00174                 cb_ukn.call();
00175             }
00176         }
00177         process_required = false;
00178     }
00179     
00180     // If we have a valid GPS time then, once per minute, set the RTC.
00181     if (theTime.status == 'A' && theTime.second == 0 && theTime.tenths == 0 && theTime.hundreths == 0) {
00182         // set_time() is defined in rtc_time.h
00183         // http://mbed.org/projects/libraries/svn/mbed/trunk/rtc_time.h
00184         set_time(theTime.to_C_tm());        
00185     }
00186     
00187 }
00188 
00189 void 
00190 GPS::pps_irq(void)
00191 {
00192     theTime.fractionalReset();
00193     theTime++; // Increment the time/date by one second. 
00194     cb_pps.call();
00195 }
00196 
00197 void 
00198 GPS::rx_irq(void)
00199 {
00200     uint32_t iir __attribute__((unused));
00201     char c;
00202     
00203     if (_base) {
00204         iir = (uint32_t)*((char *)_base + GPS_IIR); 
00205         while((int)(*((char *)_base + GPS_LSR) & 0x1)) {
00206             c = (char)(*((char *)_base + GPS_RBR) & 0xFF);             
00207             
00208             // strtok workaround. 
00209             // Found that ,, together (which some NMEA sentences
00210             // contain for a null/empty field) confuses strtok()
00211             // function. Solution:- Push a "zero" into the string 
00212             // for missing/empty fields.
00213             if (c == ',' && _lastByte == ',') {
00214                 buffer[active_buffer][rx_buffer_in] = '0';
00215                 if (++rx_buffer_in >= GPS_BUFFER_LEN) rx_buffer_in = 0;
00216             }
00217             
00218             // Debugging/dumping data. 
00219             if (_nmeaOnUart0) LPC_UART0->RBR = c; 
00220             
00221             // Put the byte into the string.
00222             buffer[active_buffer][rx_buffer_in] = c;
00223             if (++rx_buffer_in >= GPS_BUFFER_LEN) rx_buffer_in = 0;
00224             
00225             // Save for next time an irq occurs. See strtok() above.
00226             _lastByte = c;
00227             
00228             // If end of NMEA sentence flag for processing.
00229             if (c == '\n') {
00230                 active_buffer = active_buffer == 0 ? 1 : 0;
00231                 process_required = true;
00232                 rx_buffer_in = 0;                
00233             }            
00234         }
00235     }
00236 }