QRSS Rx Network receiver. A receiver to sample a segment of RF spectrum and send this data to a server for further processing and display. NXP mbed Design Challenge entry (Honorable Mention). Published in Circuit Cellar, Feb 2012
Dependencies: NetServices mbed DNSResolver
gps.cpp
00001 /*--------------------------------------------------------------------------- 00002 00003 QRSS Receiver Application 00004 00005 by Clayton ZL3TKA/VK1TKA 00006 clayton@isnotcrazy.com 00007 00008 GPS Module 00009 00010 ---------------------------------------------------------------------------*/ 00011 // include files 00012 00013 #include "gps.h" 00014 #include "comms.h" 00015 00016 // Definitions 00017 00018 #define GPS_DEBUG 0 00019 00020 // comments 00021 00022 // Macros 00023 00024 // Local Data 00025 00026 // Global Data 00027 TGPSController GPSModule; 00028 00029 00030 // Function Prototypes 00031 00032 //--------------------------------------------------------------------------- 00033 // TGPSController Class Methods 00034 //--------------------------------------------------------------------------- 00035 00036 //--------------------------------------------------------------------------- 00037 // 00038 // Constructor 00039 // 00040 TGPSController::TGPSController() : 00041 PPSInput( p30 ), 00042 GPSPort( p28, p27 ), 00043 GPSUpLED( LED3 ), 00044 PPSEvent( p30 ), 00045 bPulsed( false ), 00046 uiPPSCapture( 0 ), 00047 uiLOscCapture( 0 ) 00048 { 00049 // clear current and last line 00050 szCurrentLine[0] = 0; 00051 szLastLine[0] = 0; 00052 bNewLine = false; 00053 } 00054 00055 //--------------------------------------------------------------------------- 00056 // 00057 // Initialise routine 00058 // 00059 void TGPSController::Init() 00060 { 00061 // Set up GPS port 00062 GPSPort.baud( 4800 ); 00063 00064 // capture 1PPS event 00065 PPSEvent.rise( this, &TGPSController::PPSPulse ); 00066 00067 // Start timeout timer 00068 GPSMsgTimeout.start(); 00069 GPSPulseTimeout.start(); 00070 00071 // Set up timer hardware 00072 LPC_PINCON->PINSEL0 |= ( (0x3<<8) | (0x3<<10) ); // enable CAP2.0, CAP2.1 00073 LPC_SC->PCONP |= 1 << 22; // power up TIMER2 (PCONP[22]) 00074 LPC_SC->PCLKSEL1 &= ~(0x3<<12); 00075 LPC_SC->PCLKSEL1 |= (0x1<<12); // Timer2 PCLK = CCLK 00076 LPC_TIM2->TCR = 0x2; // reset timer 00077 LPC_TIM2->CTCR = 0x0; // timer mode 00078 LPC_TIM2->PR = 0; // no prescale 00079 LPC_TIM2->MCR = 0x0; // no match 00080 LPC_TIM2->CCR = (1<<0) | (1<<3); // Capture rising edges on both CAP2.0 & CAP2.1 00081 LPC_TIM2->TCR = 1; // start the timer 00082 } 00083 00084 //--------------------------------------------------------------------------- 00085 // 00086 // Poll routine 00087 // 00088 void TGPSController::Poll() 00089 { 00090 // Test for a 1PPS pulse 00091 if ( bPulsed ) 00092 { // 1PPS from the GPS unit 00093 bPulsed = false; 00094 GPSPulseTimeout.reset(); 00095 00096 // flush out any old serial data 00097 while ( GPSPort.readable() ) 00098 GPSPort.getc(); 00099 #if GPS_DEBUG>2 00100 printf( "***1PPS***\r\n" ); 00101 #endif 00102 // Record capture data to comms module 00103 Comms.RecordPPSTimestamps( uiPPSCapture, uiLOscCapture, GPSRecord ); 00104 } 00105 00106 // Test for GPS serial port data 00107 while ( GPSPort.readable() ) 00108 { 00109 char cNextChar = GPSPort.getc(); 00110 #if GPS_DEBUG>3 00111 printf( "%c", cNextChar ); 00112 #endif 00113 if ( ParseData(cNextChar) ) 00114 { // have a completed GPS sentence 00115 GPSMsgTimeout.reset(); 00116 // analysis the sentence data 00117 int iStatus = ProcessGPSData(); 00118 if ( iStatus==0 ) 00119 { // good sentence 00120 #if GPS_DEBUG>0 00121 printf( "Time: %d\r\n", GPSRecord.iGPSTimeSeconds ); 00122 printf( "Lat: %d\r\n", GPSRecord.iGPSLatMicroDegrees ); 00123 printf( "Long: %d\r\n", GPSRecord.iGPSLongMicroDegrees ); 00124 printf( "Alt: %d\r\n", GPSRecord.iGPSAltitudeMeters ); 00125 printf( "Sats: %d\r\n", GPSRecord.iGPSSatellites ); 00126 printf( "Qual: %d\r\n", GPSRecord.iGPSQuality ); 00127 #endif 00128 } 00129 } 00130 } 00131 00132 // Test for GPS timeout (no data) 00133 if ( GPSMsgTimeout.read_ms()>GPS_MSGTIMEOUT ) 00134 { // No GPS messages for a period 00135 #if GPS_DEBUG>1 00136 printf( "GPS Timeout - setting to offline\r\n" ); 00137 #endif 00138 GPSRecord.iGPSQuality = 0; // set quality to 0 - invalid data 00139 GPSMsgTimeout.reset(); 00140 // Record invalid GPS status to comms module 00141 Comms.RecordPPSTimestamps( 0, 0, GPSRecord ); 00142 } 00143 00144 // Test for GPS timeout (no 1PPS) 00145 if ( GPSPulseTimeout.read_ms()>GPS_PULSETIMEOUT ) 00146 { // No GPS pulse for a period 00147 // we just forward data to Comms module with invalid capture data 00148 Comms.RecordPPSTimestamps( 0, 0, GPSRecord ); 00149 GPSPulseTimeout.reset(); 00150 } 00151 00152 } 00153 00154 //--------------------------------------------------------------------------- 00155 // 00156 // Parse data from the GPS 00157 // Return true if a completed valid sentence is received 00158 // 00159 #define EXPECT_CHAR(CC) if (cChr==CC)iParseState++; else iParseState=0;ResetNumber() 00160 #define PARSE_NUMBER(NN) if(cChr==','){NN=ParseNum;ResetNumber();iParseState++;break;}if (!ParseNumber(cChr))iParseState=0 00161 #define PARSE_CHARACTER(CH) if(cChr==','){CH=cCharacter;ResetNumber();iParseState++;break;}cCharacter=cChr 00162 // 00163 bool TGPSController::ParseData( char cChr ) 00164 { 00165 ucChecksum ^= cChr; 00166 switch ( iParseState ) 00167 { 00168 case 0: 00169 if ( cChr=='$' ) 00170 iParseState++; 00171 ucChecksum = 0; 00172 break; 00173 case 1: EXPECT_CHAR('G'); break; 00174 case 2: EXPECT_CHAR('P'); break; 00175 case 3: EXPECT_CHAR('G'); break; 00176 case 4: EXPECT_CHAR('G'); break; 00177 case 5: EXPECT_CHAR('A'); break; 00178 case 6: EXPECT_CHAR(','); break; 00179 case 7: PARSE_NUMBER( GPSTime ); break; 00180 case 8: PARSE_NUMBER( GPSLatitude ); break; 00181 case 9: PARSE_CHARACTER( GPSLatNS ); break; 00182 case 10: PARSE_NUMBER( GPSLongitude ); break; 00183 case 11: PARSE_CHARACTER( GPSLongEW ); break; 00184 case 12: PARSE_NUMBER( GPSQuality ); break; 00185 case 13: PARSE_NUMBER( GPSSatellites ); break; 00186 case 14: PARSE_NUMBER( GPSDOP ); break; 00187 case 15: PARSE_NUMBER( GPSAltitude ); break; 00188 case 16: PARSE_CHARACTER( GPSAltType ); break; 00189 case 17: PARSE_NUMBER( GPSHeight ); break; 00190 case 18: PARSE_CHARACTER( GPSHeightType ); break; 00191 case 19: EXPECT_CHAR(','); 00192 ucFinalChecksum = ucChecksum; 00193 break; 00194 case 20: EXPECT_CHAR('*'); break; 00195 case 21: iParseState++; 00196 if ( (cChr>='0') && (cChr<='9') ) 00197 ucMsgChecksum = (cChr-'0') << 4; 00198 else if ( (cChr>='A') && (cChr<='F') ) 00199 ucMsgChecksum = (cChr-'A'+10) << 4; 00200 else 00201 iParseState = 0; 00202 break; 00203 case 22: iParseState++; 00204 if ( (cChr>='0') && (cChr<='9') ) 00205 ucMsgChecksum |= (cChr-'0'); 00206 else if ( (cChr>='A') && (cChr<='F') ) 00207 ucMsgChecksum |= (cChr-'A'+10); 00208 else 00209 iParseState = 0; 00210 break; 00211 case 23: // don't care about char (should be a CR) 00212 // just check the results 00213 if ( ucMsgChecksum==ucFinalChecksum ) 00214 { // Checksum okay 00215 // reset 00216 iParseState = 0; 00217 // return valid message 00218 return true; 00219 } 00220 #if GPS_DEBUG>0 00221 else 00222 printf( "!GPS Check failed - got %02X wanted %02X\r\n", (int)ucMsgChecksum, (int)ucFinalChecksum ); 00223 #endif 00224 // reset 00225 iParseState = 0; 00226 break; 00227 } 00228 00229 #if GPS_DEBUG>2 00230 // report parser state 00231 printf( ":%d:", iParseState ); 00232 #endif 00233 00234 // GPS sentence note yet completed 00235 return false; 00236 } 00237 00238 //--------------------------------------------------------------------------- 00239 // 00240 // Parse a number character by character 00241 // If character is invalid, returns false 00242 // 00243 bool TGPSController::ParseNumber( char cChar ) 00244 { 00245 // process digits 00246 if ( (cChar>='0') && (cChar<='9') ) 00247 { 00248 ParseNum.uiNumber = (ParseNum.uiNumber*10) + (cChar-'0'); 00249 ParseNum.iNumberLen++; 00250 if ( ParseNum.iNumberDecimals>=0 ) 00251 ParseNum.iNumberDecimals++; 00252 return true; 00253 } 00254 if ( cChar=='.' ) 00255 { 00256 if ( ParseNum.iNumberDecimals>=0 ) 00257 return false; // a second decimal point! 00258 ParseNum.iNumberDecimals = 0; 00259 return true; 00260 } 00261 if ( cChar=='-' ) 00262 { 00263 if ( ParseNum.iNumberLen>0 ) 00264 return false; // '-' must be the first character 00265 ParseNum.iNumberSign = -1; 00266 return true; 00267 } 00268 // otherwise an invalid character 00269 return false; 00270 } 00271 00272 //--------------------------------------------------------------------------- 00273 // 00274 // Reset the number parser 00275 // 00276 void TGPSController::ResetNumber( ) 00277 { 00278 ParseNum.uiNumber = 0; 00279 ParseNum.iNumberLen = 0; 00280 ParseNum.iNumberSign = 1; 00281 ParseNum.iNumberDecimals = -1; 00282 cCharacter = 0; 00283 } 00284 00285 00286 //--------------------------------------------------------------------------- 00287 // 00288 // Process the data from the GPS message 00289 // Returns 0 if all data is good, or an error code 00290 // 00291 int TGPSController::ProcessGPSData( ) 00292 { 00293 // check Quality 00294 if ( GPSQuality.iNumberLen<1 ) return 10; 00295 if ( GPSQuality.iNumberDecimals!=-1 ) return 11; 00296 if ( GPSQuality.iNumberSign!=1 ) return 12; 00297 // check Satellites 00298 if ( GPSSatellites.iNumberLen<1 ) return 20; 00299 if ( GPSSatellites.iNumberDecimals!=-1 ) return 21; 00300 if ( GPSSatellites.iNumberSign!=1 ) return 22; 00301 // Store sats and quality parameters 00302 GPSRecord.iGPSSatellites = GPSSatellites.uiNumber; 00303 GPSRecord.iGPSQuality = GPSQuality.uiNumber; 00304 // Check quality level 00305 if ( GPSQuality.uiNumber<1 ) return 100; // no fix 00306 // check Time 00307 if ( GPSTime.iNumberLen<6 ) return 30; 00308 if ( GPSTime.iNumberSign!=1 ) return 32; 00309 // check Latitude 00310 if ( GPSLatitude.iNumberLen!=7 ) return 40; 00311 if ( GPSLatitude.iNumberDecimals!=3 ) return 41; 00312 if ( GPSLatitude.iNumberSign!=1 ) return 42; 00313 if ( (GPSLatNS!='N') && (GPSLatNS!='S') ) return 43; 00314 // check Longitude 00315 if ( GPSLongitude.iNumberLen!=8 ) return 50; 00316 if ( GPSLongitude.iNumberDecimals!=3 ) return 51; 00317 if ( GPSLongitude.iNumberSign!=1 ) return 52; 00318 if ( (GPSLongEW!='E') && (GPSLongEW!='W') ) return 53; 00319 // check Altitude 00320 if ( GPSAltitude.iNumberLen<1 ) return 60; 00321 // Don't care about DOPs and Height and Types 00322 // Translate & Store parameters 00323 00324 // discard fractions of seconds 00325 while ( (GPSTime.iNumberDecimals--)>0 ) 00326 GPSTime.uiNumber /= 10; 00327 00328 int32_t iHours = GPSTime.uiNumber/10000; 00329 int32_t iMins = (GPSTime.uiNumber/100)%100; 00330 int32_t iSecs = GPSTime.uiNumber%100; 00331 GPSRecord.iGPSTimeSeconds = iSecs + (60*iMins) + (3600*iHours); 00332 00333 int32_t iDegrees = GPSLatitude.uiNumber / 100000; 00334 int32_t iMilliMinutes = GPSLatitude.uiNumber % 100000; 00335 GPSRecord.iGPSLatMicroDegrees = (iMilliMinutes * 100 / 6) + (iDegrees*1000000); 00336 if ( GPSLatNS=='S' ) 00337 GPSRecord.iGPSLatMicroDegrees = -GPSRecord.iGPSLatMicroDegrees; 00338 00339 iDegrees = GPSLongitude.uiNumber / 100000; 00340 iMilliMinutes = GPSLongitude.uiNumber % 100000; 00341 GPSRecord.iGPSLongMicroDegrees = (iMilliMinutes * 100 / 6) + (iDegrees*1000000); 00342 if ( GPSLongEW=='W' ) 00343 GPSRecord.iGPSLatMicroDegrees = -GPSRecord.iGPSLatMicroDegrees; 00344 00345 GPSRecord.iGPSAltitudeMeters = GPSAltitude.uiNumber * GPSAltitude.iNumberSign; 00346 while ( (GPSAltitude.iNumberDecimals--)>0 ) 00347 GPSRecord.iGPSAltitudeMeters /= 10; 00348 00349 return 0; 00350 } 00351 00352 //--------------------------------------------------------------------------- 00353 // 00354 // PPS Event routine 00355 // 00356 void TGPSController::PPSPulse() 00357 { 00358 // indicate we have pulsed 00359 bPulsed = true; 00360 00361 // capture timer capture registers 00362 // 1PPP = CAP2.0 00363 // LOsc (/4096) = CAP2.1 00364 uiPPSCapture = LPC_TIM2->CR0; 00365 uiLOscCapture = LPC_TIM2->CR1; 00366 00367 } 00368 00369 /* 00370 GPS Messages: 00371 00372 GGA - essential fix data which provide 3D location and accuracy data. 00373 00374 $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47 00375 00376 Where: 00377 GGA Global Positioning System Fix Data 00378 123519 Fix taken at 12:35:19 UTC 00379 4807.038,N Latitude 48 deg 07.038' N 00380 01131.000,E Longitude 11 deg 31.000' E 00381 1 Fix quality: 0 = invalid 00382 1 = GPS fix (SPS) 00383 2 = DGPS fix 00384 3 = PPS fix 00385 4 = Real Time Kinematic 00386 5 = Float RTK 00387 6 = estimated (dead reckoning) (2.3 feature) 00388 7 = Manual input mode 00389 8 = Simulation mode 00390 08 Number of satellites being tracked 00391 0.9 Horizontal dilution of position 00392 545.4,M Altitude, Meters, above mean sea level 00393 46.9,M Height of geoid (mean sea level) above WGS84 00394 ellipsoid 00395 (empty field) time in seconds since last DGPS update 00396 (empty field) DGPS station ID number 00397 *47 the checksum data, always begins with * 00398 00399 00400 VTG - Velocity made good. The gps receiver may use the LC prefix instead of GP if it is emulating Loran output. 00401 00402 $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48 00403 00404 where: 00405 VTG Track made good and ground speed 00406 054.7,T True track made good (degrees) 00407 034.4,M Magnetic track made good 00408 005.5,N Ground speed, knots 00409 010.2,K Ground speed, Kilometers per hour 00410 *48 Checksum 00411 00412 00413 00414 $GPGGA,,,,,,0,05,,,,,,,*63 00415 $GPGGA,,,,,,0,02,,,,,,,*64 00416 $GPGGA,,,,,,0,03,,,,,,,*65 00417 $GPGGA,120609.46,3515.405,S,14904.873,E,0,04,2.24,718,M,14,M,,*42 00418 $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48 00419 $GPGGA,120610.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*4B 00420 $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48 00421 $GPGGA,120611.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*4A 00422 $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48 00423 $GPGGA,120612.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*49 00424 00425 */ 00426 00427 //--------------------------------------------------------------------------- 00428 // END 00429 //--------------------------------------------------------------------------- 00430
Generated on Wed Jul 13 2022 23:08:21 by 1.7.2