// we need to parse GLL as well because it can mark the start of a new quantum data // followed by values with no data, ex. altitude, vario, etc. BOOL NMEAParser::GLL(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *GPS_INFO) { gpsValid = !NAVWarn(params[5][0]); if (!activeGPS) return TRUE; if (ReplayLogger::IsEnabled()) { // block actual GPS signal InterfaceTimeoutReset(); return TRUE; } GPS_INFO->NAVWarning = !gpsValid; // use valid time with invalid fix double glltime = StrToDouble(params[4],NULL); if (glltime>0) { #ifdef NEWTRIGGERGPS double ThisTime = TimeConvert(glltime, GPS_INFO); // 091208 #else double ThisTime = TimeModify(glltime, GPS_INFO); #endif #ifndef NEWTRIGGERGPS if (!TimeHasAdvanced(ThisTime, GPS_INFO)) return FALSE; // 091208 #endif #ifdef NEWTRIGGERGPS // is time advanced to a new quantum? if (ThisTime >NmeaTime) { // yes so lets trigger the gps event TriggerGPSUpdate(); Sleep(50); // 091208 NmeaTime=ThisTime; TimeSet(GPS_INFO); // 091208 TimeHasAdvanced(ThisTime,GPS_INFO); // 091208 //StartupStore(_T(".............. trigger from GLL\n")); } #endif } if (!gpsValid) return FALSE; // 091108 addon BUGFIX GLL time with no valid signal double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[0], NULL)); tmplat = NorthOrSouth(tmplat, params[1][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplon = EastOrWest(tmplon,params[3][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; } else { } return TRUE; }
// we need to parse GLL as well because it can mark the start of a new quantum data // followed by values with no data, ex. altitude, vario, etc. BOOL NMEAParser::GLL(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { gpsValid = !NAVWarn(params[5][0]); GPSCONNECT=TRUE; if (!activeGPS) return TRUE; pGPS->NAVWarning = !gpsValid; // use valid time with invalid fix GLLtime = StrToDouble(params[4],NULL); if (!RMCAvailable && !GGAAvailable && (GLLtime>0)) { #ifndef OLD_TIME_MODIFY double ThisTime = TimeModify(params[4], pGPS, StartDay); #else double ThisTime = TimeModify(GLLtime, pGPS); #endif if (!TimeHasAdvanced(ThisTime, pGPS)) return FALSE; } if (!gpsValid) return FALSE; double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[0], NULL)); tmplat = NorthOrSouth(tmplat, params[1][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplon = EastOrWest(tmplon,params[3][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; } else { } return TRUE; } // END GLL
double NMEAParser::TimeModify(double FixTime, NMEA_INFO* pGPS) { static int day_difference=0, previous_months_day_difference=0; double hours, mins,secs; hours = FixTime / 10000; pGPS->Hour = (int)hours; mins = FixTime / 100; mins = mins - (pGPS->Hour*100); pGPS->Minute = (int)mins; secs = FixTime - (pGPS->Hour*10000) - (pGPS->Minute*100); pGPS->Second = (int)secs; FixTime = secs + (pGPS->Minute*60) + (pGPS->Hour*3600); #else double TimeModify(const TCHAR* StrTime, NMEA_INFO* pGPS, int& StartDay) { double secs = 0.0; if (_istdigit(StrTime[0]) && _istdigit(StrTime[1])) { pGPS->Hour = (StrTime[0] - '0')*10 + (StrTime[1] - '0'); } if (_istdigit(StrTime[2]) && _istdigit(StrTime[3])) { pGPS->Minute = (StrTime[2] - '0')*10 + (StrTime[3] - '0'); } if (_istdigit(StrTime[4]) && _istdigit(StrTime[5])) { pGPS->Second = (StrTime[4] - '0')*10 + (StrTime[5] - '0'); } if (StrTime[6] == '.') { int i = 7; while (_istdigit(StrTime[i])) { double tmp = (StrTime[i] - '0')*0.1; for (int j = 7; j < i; ++j) { tmp *= 0.1; } secs += tmp; ++i; } } return secs + TimeModify(pGPS, StartDay); }
static BOOL FLYSEN(PDeviceDescriptor_t d, TCHAR *String, NMEA_INFO *pGPS) { TCHAR ctemp[80]; double vtas; static int offset=-1; d->nmeaParser.connected = true; // firmware 3.31h no offset // firmware 3.32 1 offset // Determine firmware version, assuming it will not change in the session! if (offset<0) { NMEAParser::ExtractParameter(String,ctemp,8); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=0; else { NMEAParser::ExtractParameter(String,ctemp,9); if ( (_tcscmp(ctemp,_T("A"))==0) || (_tcscmp(ctemp,_T("V"))==0)) offset=1; else return TRUE; } } // VOID GPS SIGNAL NMEAParser::ExtractParameter(String,ctemp,8+offset); if (_tcscmp(ctemp,_T("V"))==0) { pGPS->NAVWarning=true; // GPSCONNECT=false; // 121127 NO!! goto label_nogps; } // ------------------------ double tmplat; double tmplon; NMEAParser::ExtractParameter(String,ctemp,1+offset); tmplat = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,2+offset); tmplat = NorthOrSouth(tmplat, ctemp[0]); NMEAParser::ExtractParameter(String,ctemp,3+offset); tmplon = MixedFormatToDegrees(StrToDouble(ctemp, NULL)); NMEAParser::ExtractParameter(String,ctemp,4+offset); tmplon = EastOrWest(tmplon,ctemp[0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; pGPS->NAVWarning=false; } // GPS SPEED NMEAParser::ExtractParameter(String,ctemp,6+offset); pGPS->Speed = StrToDouble(ctemp,NULL)/10; // TRACK BEARING if (pGPS->Speed>1.0) { NMEAParser::ExtractParameter(String,ctemp,5+offset); pGPS->TrackBearing = AngleLimit360(StrToDouble(ctemp, NULL)); } // HGPS NMEAParser::ExtractParameter(String,ctemp,7+offset); pGPS->Altitude = StrToDouble(ctemp,NULL); // ------------------------ label_nogps: // SATS NMEAParser::ExtractParameter(String,ctemp,9+offset); pGPS->SatellitesUsed = (int) StrToDouble(ctemp,NULL); // DATE // Firmware 3.32 has got the date if (offset>0) { NMEAParser::ExtractParameter(String,ctemp,0); long gy, gm, gd; TCHAR *Stop; gy = _tcstol(&ctemp[4], &Stop, 10) + 2000; ctemp[4] = '\0'; gm = _tcstol(&ctemp[2], &Stop, 10); ctemp[2] = '\0'; gd = _tcstol(&ctemp[0], &Stop, 10); if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { pGPS->Year = gy; pGPS->Month = gm; pGPS->Day = gd; } } // TIME // ignoring 00:00.00 // We need to manage UTC time #ifndef OLD_TIME_MODIFY static int StartDay=-1; if (pGPS->SatellitesUsed>0) { NMEAParser::ExtractParameter(String,ctemp,0+offset); pGPS->Time = TimeModify(ctemp, pGPS, StartDay); } // TODO : check if TimeHasAdvanced check is needed (cf. Parser.cpp) #else NMEAParser::ExtractParameter(String,ctemp,0+offset); double fixTime = StrToDouble(ctemp,NULL); static int day_difference=0, previous_months_day_difference=0; static int startday=-1; if (fixTime>0 && pGPS->SatellitesUsed>0) { double hours, mins,secs; hours = fixTime / 10000; pGPS->Hour = (int)hours; mins = fixTime / 100; mins = mins - (pGPS->Hour*100); pGPS->Minute = (int)mins; secs = fixTime - (pGPS->Hour*10000) - (pGPS->Minute*100); pGPS->Second = (int)secs; fixTime = secs + (pGPS->Minute*60) + (pGPS->Hour*3600); if ((startday== -1) && (pGPS->Day != 0)) { if (offset) StartupStore(_T(". FLYSEN First GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); else StartupStore(_T(". FLYSEN No Date, using PNA GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); startday = pGPS->Day; day_difference=0; previous_months_day_difference=0; } if (startday != -1) { if (pGPS->Day < startday) { // detect change of month (e.g. day=1, startday=26) previous_months_day_difference=day_difference+1; day_difference=0; startday = pGPS->Day; StartupStore(_T(". FLYSEN Change GPS DATE to NEW MONTH: %d-%d-%d (%d days running)%s"), pGPS->Year, pGPS->Month, pGPS->Day,previous_months_day_difference,NEWLINE); } if ( (pGPS->Day-startday)!=day_difference) { StartupStore(_T(". FLYSEN Change GPS DATE: %d-%d-%d%s"), pGPS->Year, pGPS->Month, pGPS->Day,NEWLINE); } day_difference = pGPS->Day-startday; if ((day_difference+previous_months_day_difference)>0) { fixTime += (day_difference+previous_months_day_difference) * 86400; } } pGPS->Time = fixTime; } #endif // HPA from the pressure sensor // NMEAParser::ExtractParameter(String,ctemp,10+offset); // double ps = StrToDouble(ctemp,NULL)/100; // pGPS->BaroAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // HBAR 1013.25 NMEAParser::ExtractParameter(String,ctemp,11+offset); double palt=StrToDouble(ctemp,NULL); UpdateBaroSource( pGPS, 0,d, QNEAltitudeToQNHAltitude(palt)); // VARIO NMEAParser::ExtractParameter(String,ctemp,12+offset); pGPS->Vario = StrToDouble(ctemp,NULL)/100; // TAS NMEAParser::ExtractParameter(String,ctemp,13+offset); vtas=StrToDouble(ctemp,NULL)/10; pGPS->IndicatedAirspeed = vtas/AirDensityRatio(palt); pGPS->TrueAirspeed = vtas; if (pGPS->IndicatedAirspeed >0) pGPS->AirspeedAvailable = TRUE; else pGPS->AirspeedAvailable = FALSE; // ignore n.14 airspeed source // OAT NMEAParser::ExtractParameter(String,ctemp,15+offset); pGPS->OutsideAirTemperature = StrToDouble(ctemp,NULL); pGPS->TemperatureAvailable=TRUE; // ignore n.16 baloon temperature // BATTERY PERCENTAGES NMEAParser::ExtractParameter(String,ctemp,17+offset); pGPS->ExtBatt1_Voltage = StrToDouble(ctemp,NULL)+1000; NMEAParser::ExtractParameter(String,ctemp,18+offset); pGPS->ExtBatt2_Voltage = StrToDouble(ctemp,NULL)+1000; pGPS->VarioAvailable = TRUE; // currently unused in LK, but ready for next future TriggerVarioUpdate(); TriggerGPSUpdate(); return TRUE; }
BOOL NMEAParser::GGA(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { GGAAvailable = TRUE; GPSCONNECT = TRUE; // 091208 // this will force gps invalid but will NOT assume gps valid! nSatellites = (int)(min(16.0, StrToDouble(params[6], NULL))); if (nSatellites==0) { gpsValid = false; } double ggafix = StrToDouble(params[5],NULL); if ( ggafix==0 || ggafix>5 ) { #ifdef DEBUG_GPS if (ggafix>5) StartupStore(_T("------ GGA DEAD RECKON fix skipped%s"),NEWLINE); #endif gpsValid=false; } else { gpsValid=true; } if (!activeGPS) return TRUE; pGPS->SatellitesUsed = nSatellites; // 091208 pGPS->NAVWarning = !gpsValid; // 091208 GGAtime=StrToDouble(params[0],NULL); // Even with invalid fix, we might still have valid time // I assume that 0 is invalid, and I am very sorry for UTC time 00:00 ( missing a second a midnight). // is better than risking using 0 as valid, since many gps do not respect any real nmea standard // // Update 121215: do not update time with GGA if RMC is found, because at 00UTC only RMC will set the date change! // Remember that we trigger update of calculations when we get GGA. // So what happens if the gps sequence is GGA and then RMC? // 2359UTC: // GGA , old date, trigger gps calc // RMC, old date // 0000UTC: // GGA, old date even if new date will come for the same quantum, // GGAtime>0, see (*) // BANG! oldtime from RMC is 2359, new time from GGA is 0, time is in the past! // // If the gps is sending first RMC, this problem does not appear of course. // // (*) IMPORTANT> GGAtime at 00UTC will most likely be >0! Because time is in hhmmss.ss .ss is always >0!! // We check GGAtime, RMCtime, GLLtime etc. for 0 because in case of error the gps will send 000000.000 !! // if ( (!RMCAvailable && (GGAtime>0)) || ((GGAtime>0) && (GGAtime == RMCtime)) ) { // RMC already came in same time slot #if DEBUGSEQ StartupStore(_T("... GGA update time = %f RMCtime=%f\n"),GGAtime,RMCtime); // 31C #endif double ThisTime = TimeModify(GGAtime, pGPS); if (!TimeHasAdvanced(ThisTime, pGPS)) { #if DEBUGSEQ StartupStore(_T(".... GGA time not advanced, skip\n")); // 31C #endif return FALSE; } } if (gpsValid) { double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[1], NULL)); tmplat = NorthOrSouth(tmplat, params[2][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[3], NULL)); tmplon = EastOrWest(tmplon,params[4][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; } else { #ifdef DEBUG_GPS StartupStore(_T("++++++ GGA gpsValid with invalid posfix!%s"),NEWLINE); #endif gpsValid=false; } } // GGA is marking now triggering end of data, so OK to use baro // Even with invalid fix we might have valid baro data of course // any NMEA sentence with time can now trigger gps update: the first to detect new time will make trigger. // we assume also that any sentence with no time belongs to current time. // note that if no time from gps, no use of vario and baro data, but also no fix available.. so no problems if(RMZAvailable) { UpdateBaroSource(pGPS, isFlarm? BARO__RMZ_FLARM:BARO__RMZ, NULL, RMZAltitude); } else if(RMAAvailable) { UpdateBaroSource(pGPS, BARO__RMA,NULL, RMAAltitude); } // If no gps fix, at this point we trigger refresh and quit if (!gpsValid) { #if DEBUGSEQ StartupStore(_T("........ GGA no gps valid, triggerGPS!\n")); // 31C #endif TriggerGPSUpdate(); return FALSE; } // "Altitude" should always be GPS Altitude. pGPS->Altitude = ParseAltitude(params[8], params[9]); pGPS->Altitude += (GPSAltitudeOffset/1000); // BUGFIX 100429 double GeoidSeparation; if (_tcslen(params[10])>0) { // No real need to parse this value, // but we do assume that no correction is required in this case GeoidSeparation = ParseAltitude(params[10], params[11]); } else { if (UseGeoidSeparation) { GeoidSeparation = LookupGeoidSeparation(pGPS->Latitude, pGPS->Longitude); pGPS->Altitude -= GeoidSeparation; } } // if RMC would be Triggering update, we loose the relative altitude, which is coming AFTER rmc! // This was causing old altitude recorded in new pos fix. // 120428: // GGA will trigger gps if there is no RMC, // or if GGAtime is the same as RMCtime, which means that RMC already came and we are last in the sequence if ( !RMCAvailable || (GGAtime == RMCtime) ) { #if DEBUGSEQ StartupStore(_T("... GGA trigger gps, GGAtime==RMCtime\n")); // 31C #endif TriggerGPSUpdate(); } return TRUE; } // END GGA
BOOL NMEAParser::RMC(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { TCHAR *Stop; static bool logbaddate=true; double speed=0; gpsValid = !NAVWarn(params[1][0]); GPSCONNECT = TRUE; RMCAvailable=true; // 100409 #ifdef PNA if (DeviceIsGM130) { double ps = GM130BarPressure(); RMZAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; // StartupStore(_T("....... Pressure=%.0f QNH=%.2f Altitude=%.1f\n"),ps,QNH,RMZAltitude); RMZAvailable = TRUE; UpdateBaroSource(pGPS, BARO__GM130, NULL, RMZAltitude); } if (DeviceIsRoyaltek3200) { if (Royaltek3200_ReadBarData()) { double ps = Royaltek3200_GetPressure(); RMZAltitude = (1 - pow(fabs(ps / QNH), 0.190284)) * 44307.69; #if 0 pGPS->TemperatureAvailable=true; pGPS->OutsideAirTemperature = Royaltek3200_GetTemperature(); #endif } RMZAvailable = TRUE; UpdateBaroSource(pGPS, BARO__ROYALTEK3200, NULL, RMZAltitude); } #endif // PNA if (!activeGPS) return TRUE; // if no valid fix, we dont get speed either! if (gpsValid) { // speed is in knots, 2 = 3.7kmh speed = StrToDouble(params[6], NULL); } pGPS->NAVWarning = !gpsValid; // say we are updated every time we get this, // so infoboxes get refreshed if GPS connected // the RMC sentence marks the start of a new fix, so we force the old data to be saved for calculations // Even with no valid position, we let RMC set the time and date if valid long gy, gm, gd; gy = _tcstol(¶ms[8][4], &Stop, 10) + 2000; params[8][4] = '\0'; gm = _tcstol(¶ms[8][2], &Stop, 10); params[8][2] = '\0'; gd = _tcstol(¶ms[8][0], &Stop, 10); // SeeYou PC is sending NMEA sentences with RMC date 2072-02-27 if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { pGPS->Year = gy; pGPS->Month = gm; pGPS->Day = gd; force_advance: RMCtime = StrToDouble(params[0],NULL); double ThisTime = TimeModify(RMCtime, pGPS); // RMC time has priority on GGA and GLL etc. so if we have it we use it at once if (!TimeHasAdvanced(ThisTime, pGPS)) { #if DEBUGSEQ StartupStore(_T("..... RMC time not advanced, skipping \n")); // 31C #endif return FALSE; } } else { if (devIsCondor(devA())) { #if DEBUGSEQ StartupStore(_T(".. Condor not sending valid date, using 1.1.2012%s"),NEWLINE); #endif gy=2012; gm=1; gd=1; goto force_advance; } if (gpsValid && logbaddate) { // 091115 StartupStore(_T("------ NMEAParser:RMC Receiving an invalid or null DATE from GPS%s"),NEWLINE); StartupStore(_T("------ NMEAParser: Date received is y=%d m=%d d=%d%s"),gy,gm,gd,NEWLINE); // 100422 StartupStore(_T("------ This message will NOT be repeated.%s"),NEWLINE); DoStatusMessage(MsgToken(875)); logbaddate=false; } gy=2012; gm=2; gd=30; // an impossible date! goto force_advance; } if (gpsValid) { double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplat = NorthOrSouth(tmplat, params[3][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[4], NULL)); tmplon = EastOrWest(tmplon,params[5][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { pGPS->Latitude = tmplat; pGPS->Longitude = tmplon; } pGPS->Speed = KNOTSTOMETRESSECONDS * speed; if (pGPS->Speed>trackbearingminspeed) { pGPS->TrackBearing = AngleLimit360(StrToDouble(params[7], NULL)); } } // gpsvalid 091108 // As soon as we get a fix for the first time, set the // system clock to the GPS time. static bool sysTimeInitialised = false; if (!pGPS->NAVWarning && (gpsValid)) { if (SetSystemTimeFromGPS) { if (!sysTimeInitialised) { if ( ( pGPS->Year > 1980 && pGPS->Year<2100) && ( pGPS->Month > 0) && ( pGPS->Hour > 0)) { sysTimeInitialised =true; // Attempting only once SYSTEMTIME sysTime; // ::GetSystemTime(&sysTime); int hours = (int)pGPS->Hour; int mins = (int)pGPS->Minute; int secs = (int)pGPS->Second; sysTime.wYear = (unsigned short)pGPS->Year; sysTime.wMonth = (unsigned short)pGPS->Month; sysTime.wDay = (unsigned short)pGPS->Day; sysTime.wHour = (unsigned short)hours; sysTime.wMinute = (unsigned short)mins; sysTime.wSecond = (unsigned short)secs; sysTime.wMilliseconds = 0; ::SetSystemTime(&sysTime); } } } } if(RMZAvailable) { UpdateBaroSource(pGPS, BARO__RMZ, NULL, RMZAltitude); } else if(RMAAvailable) { UpdateBaroSource(pGPS, BARO__RMA, NULL, RMAAltitude); } if (!GGAAvailable) { // update SatInUse, some GPS receiver dont emmit GGA sentance if (!gpsValid) { pGPS->SatellitesUsed = 0; } else { pGPS->SatellitesUsed = -1; } } if ( !GGAAvailable || (GGAtime == RMCtime) ) { #if DEBUGSEQ StartupStore(_T("... RMC trigger gps, GGAtime==RMCtime\n")); // 31C #endif TriggerGPSUpdate(); } return TRUE; } // END RMC
BOOL NMEAParser::ParseGPS_POSITION_internal(const GPS_POSITION& loc, NMEA_INFO& GPSData) { gpsValid = !(loc.dwFlags & GPS_DATA_FLAGS_HARDWARE_OFF); if (!gpsValid) { return TRUE; } GPSCONNECT=TRUE; switch (loc.FixType) { case GPS_FIX_UNKNOWN: gpsValid = false; break; case GPS_FIX_2D: case GPS_FIX_3D: gpsValid = true; break; default: break; } if (loc.dwValidFields & GPS_VALID_SATELLITE_COUNT) { nSatellites = loc.dwSatelliteCount; } if(!activeGPS) { return TRUE; } GPSData.SatellitesUsed = nSatellites; GPSData.NAVWarning = !gpsValid; if (loc.dwValidFields & GPS_VALID_UTC_TIME) { GPSData.Hour = loc.stUTCTime.wHour; GPSData.Minute = loc.stUTCTime.wMinute; GPSData.Second = loc.stUTCTime.wSecond; GPSData.Month = loc.stUTCTime.wMonth; GPSData.Day = loc.stUTCTime.wDay; GPSData.Year = loc.stUTCTime.wYear; if(!TimeHasAdvanced(TimeModify(&GPSData, StartDay), &GPSData)) { return FALSE; } } if (loc.dwValidFields & GPS_VALID_LATITUDE) { GPSData.Latitude = loc.dblLatitude; } if (loc.dwValidFields & GPS_VALID_LONGITUDE) { GPSData.Longitude = loc.dblLongitude; } if (loc.dwValidFields & GPS_VALID_SPEED) { GPSData.Speed = KNOTSTOMETRESSECONDS * loc.flSpeed; } if (loc.dwValidFields & GPS_VALID_HEADING) { if (GPSData.Speed>trackbearingminspeed) { GPSData.TrackBearing = AngleLimit360(loc.flHeading); } } if (loc.dwValidFields & GPS_VALID_MAGNETIC_VARIATION) { } if (loc.dwValidFields & GPS_VALID_ALTITUDE_WRT_SEA_LEVEL) { GPSData.Altitude = loc.flAltitudeWRTSeaLevel; GPSData.Altitude += (GPSAltitudeOffset/1000); // BUGFIX 100429 } #if 0 if (loc.dwValidFields & GPS_VALID_ALTITUDE_WRT_ELLIPSOID) { /* MSDN says.. * "flAltitudeWRTEllipsoid : Altitude, in meters, with respect to the WGS84 ellipsoid. " * "flAltitudeWRTSeaLevel : Altitude, in meters, with respect to sea level. " * * But when I get this structure, flAltitudeWRTSeaLevel field has proper value. But, * flAltitudeWRTEllipsoid field has different meaning value. * * But flAltitudeWRTEllipsoid field contains just geodial separation. */ } #endif if (loc.dwValidFields & GPS_VALID_POSITION_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_HORIZONTAL_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_VERTICAL_DILUTION_OF_PRECISION) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_USED_PRNS) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_PRNS) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_ELEVATION) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_AZIMUTH) { } if (loc.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW_SIGNAL_TO_NOISE_RATIO) { } if(gpsValid && !GPSData.NAVWarning && GPSData.SatellitesUsed == 0) { GPSData.SatellitesUsed = -1; } TriggerGPSUpdate(); return TRUE; }
BOOL NMEAParser::GGA(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *GPS_INFO) { if (ReplayLogger::IsEnabled()) { return TRUE; } GGAAvailable = TRUE; GPSCONNECT = TRUE; // 091208 // this will force gps invalid but will NOT assume gps valid! nSatellites = (int)(min(16.0, StrToDouble(params[6], NULL))); if (nSatellites==0) { gpsValid = false; } double ggafix = StrToDouble(params[5],NULL); if ( ggafix==0 || ggafix>5 ) { #ifdef DEBUG_GPS if (ggafix>5) StartupStore(_T("------ GGA DEAD RECKON fix skipped%s"),NEWLINE); #endif gpsValid=false; } else { gpsValid=true; } // don't set any GPS_INFO if not activeGPS!! if (!activeGPS) return TRUE; GPS_INFO->SatellitesUsed = nSatellites; // 091208 GPS_INFO->NAVWarning = !gpsValid; // 091208 // // GPS_INFO->SatellitesUsed = (int)(min(16,StrToDouble(params[6], NULL))); 091205 091208 moved up // GPS_INFO->SatellitesUsed = nSatellites; // 091205 double ggatime=StrToDouble(params[0],NULL); // Even with invalid fix, we might still have valid time // I assume that 0 is invalid, and I am very sorry for UTC time 00:00 ( missing a second a midnight). // is better than risking using 0 as valid, since many gps do not respect any real nmea standard if (ggatime>0) { #ifdef NEWTRIGGERGPS double ThisTime = TimeConvert(ggatime, GPS_INFO); #else double ThisTime = TimeModify(ggatime, GPS_INFO); #endif #ifndef NEWTRIGGERGPS if (!TimeHasAdvanced(ThisTime, GPS_INFO)) return FALSE; #endif #ifdef NEWTRIGGERGPS // is time advanced to a new quantum? if (ThisTime >NmeaTime) { // yes so lets trigger the gps event TriggerGPSUpdate(); Sleep(50); // 091208 NmeaTime=ThisTime; TimeSet(GPS_INFO); // 091208 TimeHasAdvanced(ThisTime, GPS_INFO); // 091208 StartupStore(_T(".............. trigger from GGA\n")); } #endif } if (gpsValid) { double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[1], NULL)); tmplat = NorthOrSouth(tmplat, params[2][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[3], NULL)); tmplon = EastOrWest(tmplon,params[4][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; } else { #ifdef DEBUG_GPS StartupStore(_T("++++++ GGA gpsValid with invalid posfix!%s"),NEWLINE); #endif gpsValid=false; } } // GGA is marking now triggering end of data, so OK to use baro // Even with invalid fix we might have valid baro data of course // any NMEA sentence with time can now trigger gps update: the first to detect new time will make trigger. // we assume also that any sentence with no time belongs to current time. // note that if no time from gps, no use of vario and baro data, but also no fix available.. so no problems if(RMZAvailable) { GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMZAltitude; } else if(RMAAvailable) { GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMAAltitude; } #ifndef NEWTRIGGERGPS if (!gpsValid) { // 091108 addon BUGFIX GCA // in old mode, GGA had priority over RMC for triggering, so this was needed in case of no signal TriggerGPSUpdate(); // 091205 TESTFIX return FALSE; // 091108 addon BUGFIX GCA } #endif // "Altitude" should always be GPS Altitude. GPS_INFO->Altitude = ParseAltitude(params[8], params[9]); GPS_INFO->Altitude += (GPSAltitudeOffset/1000); // BUGFIX 100429 double GeoidSeparation; if (_tcslen(params[10])>0) { // No real need to parse this value, // but we do assume that no correction is required in this case GeoidSeparation = ParseAltitude(params[10], params[11]); } else { if (UseGeoidSeparation) { GeoidSeparation = LookupGeoidSeparation(GPS_INFO->Latitude, GPS_INFO->Longitude); GPS_INFO->Altitude -= GeoidSeparation; } } #ifndef NEWTRIGGERGPS // if RMC would be Triggering update, we loose the relative altitude, which is coming AFTER rmc! // This was causing old altitude recorded in new pos fix. TriggerGPSUpdate(); #endif return TRUE; }
BOOL NMEAParser::RMC(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *GPS_INFO) { TCHAR *Stop; static bool logbaddate=true; double speed=0; gpsValid = !NAVWarn(params[1][0]); GPSCONNECT = TRUE; RMCAvailable=true; // 100409 if (!activeGPS) return TRUE; // 091205 BUGFIX true // if no valid fix, we dont get speed either! if (gpsValid) { speed = StrToDouble(params[6], NULL); // speed is in knots, 2 = 3.7kmh if (speed>2.0) { GPS_INFO->MovementDetected = TRUE; if (ReplayLogger::IsEnabled()) { // stop logger replay if aircraft is actually moving. ReplayLogger::Stop(); } } else { GPS_INFO->MovementDetected = FALSE; if (ReplayLogger::IsEnabled()) { // block actual GPS signal if not moving and a log is being replayed return TRUE; } } } GPS_INFO->NAVWarning = !gpsValid; // say we are updated every time we get this, // so infoboxes get refreshed if GPS connected // the RMC sentence marks the start of a new fix, so we force the old data to be saved for calculations #ifndef NEWTRIGGERGPS if (!GGAAvailable) { TriggerGPSUpdate(); } #endif // Even with no valid position, we let RMC set the time and date if valid long gy, gm, gd; gy = _tcstol(¶ms[8][4], &Stop, 10) + 2000; params[8][4] = '\0'; gm = _tcstol(¶ms[8][2], &Stop, 10); params[8][2] = '\0'; gd = _tcstol(¶ms[8][0], &Stop, 10); // SeeYou PC is sending NMEA sentences with RMC date 2072-02-27 if ( ((gy > 1980) && (gy <2100) ) && (gm != 0) && (gd != 0) ) { GPS_INFO->Year = gy; GPS_INFO->Month = gm; GPS_INFO->Day = gd; #ifdef NEWTRIGGERGPS double ThisTime = TimeConvert(StrToDouble(params[0],NULL), GPS_INFO); // 091208 #else double ThisTime = TimeModify(StrToDouble(params[0],NULL), GPS_INFO); #endif #ifndef NEWTRIGGERGPS if (!TimeHasAdvanced(ThisTime, GPS_INFO)) return FALSE; #endif #ifdef NEWTRIGGERGPS // is time advanced to a new quantum? if (ThisTime >NmeaTime) { // yes so lets trigger the gps event TriggerGPSUpdate(); // and only then advance the time in the GPSINFO Sleep(50); // 091208 NmeaTime=ThisTime; TimeSet(GPS_INFO); // 091208 TimeHasAdvanced(ThisTime, GPS_INFO); // 091208 StartupStore(_T(".............. trigger from RMC\n")); } #endif } else { if (gpsValid && logbaddate) { // 091115 StartupStore(_T("------ NMEAParser:RMC Receiving an invalid or null DATE from GPS%s"),NEWLINE); StartupStore(_T("------ NMEAParser: Date received is y=%d m=%d d=%d%s"),gy,gm,gd,NEWLINE); // 100422 StartupStore(_T("------ This message will NOT be repeated.%s"),NEWLINE); // DoStatusMessage(_T("WARNING: GPS IS SENDING INVALID DATE, AND PROBABLY WRONG TIME")); // REMOVE FIXV2 // LKTOKEN 875 WARNING: GPS IS SENDING INVALID DATE, AND PROBABLY WRONG TIME")); DoStatusMessage(gettext(TEXT("_@M875_"))); logbaddate=false; } } // } // 091108 if (gpsValid) { // 091108 BUGFIX set latlon and speed ONLY if valid gpsdata, missing check! double tmplat; double tmplon; tmplat = MixedFormatToDegrees(StrToDouble(params[2], NULL)); tmplat = NorthOrSouth(tmplat, params[3][0]); tmplon = MixedFormatToDegrees(StrToDouble(params[4], NULL)); tmplon = EastOrWest(tmplon,params[5][0]); if (!((tmplat == 0.0) && (tmplon == 0.0))) { GPS_INFO->Latitude = tmplat; GPS_INFO->Longitude = tmplon; } GPS_INFO->Speed = KNOTSTOMETRESSECONDS * speed; if (GPS_INFO->Speed>1.0) { // JMW don't update bearing unless we're moving GPS_INFO->TrackBearing = AngleLimit360(StrToDouble(params[7], NULL)); } } // gpsvalid 091108 // Altair doesn't have a battery-backed up realtime clock, // so as soon as we get a fix for the first time, set the // system clock to the GPS time. static bool sysTimeInitialised = false; if (!GPS_INFO->NAVWarning && (gpsValid)) { if (SetSystemTimeFromGPS) { if (!sysTimeInitialised) { if ( ( GPS_INFO->Year > 1980 && GPS_INFO->Year<2100) && ( GPS_INFO->Month > 0) && ( GPS_INFO->Hour > 0)) { sysTimeInitialised =true; // Attempting only once SYSTEMTIME sysTime; // ::GetSystemTime(&sysTime); int hours = (int)GPS_INFO->Hour; int mins = (int)GPS_INFO->Minute; int secs = (int)GPS_INFO->Second; sysTime.wYear = (unsigned short)GPS_INFO->Year; sysTime.wMonth = (unsigned short)GPS_INFO->Month; sysTime.wDay = (unsigned short)GPS_INFO->Day; sysTime.wHour = (unsigned short)hours; sysTime.wMinute = (unsigned short)mins; sysTime.wSecond = (unsigned short)secs; sysTime.wMilliseconds = 0; ::SetSystemTime(&sysTime); } } } } if (!ReplayLogger::IsEnabled()) { if(RMZAvailable) { // JMW changed from Altitude to BaroAltitude GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMZAltitude; } else if(RMAAvailable) { // JMW changed from Altitude to BaroAltitude GPS_INFO->BaroAltitudeAvailable = true; GPS_INFO->BaroAltitude = RMAAltitude; } } if (!GGAAvailable) { // update SatInUse, some GPS receiver dont emmit GGA sentance if (!gpsValid) { GPS_INFO->SatellitesUsed = 0; } else { GPS_INFO->SatellitesUsed = -1; } } return TRUE; }