Sergey S / MODGPS

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