Matthias Prinke / MODGPS

Dependents:   GPSDevice LogData_UM6-to-SDcard UM6withGPS mbed-cansat-test-GPS ... more

Fork of MODGPS by Andy K

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