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
JNIEXPORT void JNICALL Java_org_xcsoar_InternalGPS_setLocation(JNIEnv *env, jobject obj, jlong time, jint n_satellites, jdouble longitude, jdouble latitude, jboolean hasAltitude, jdouble altitude, jboolean hasBearing, jdouble bearing, jboolean hasSpeed, jdouble speed, jboolean hasAccuracy, jdouble accuracy, jboolean hasAcceleration, jdouble acceleration) { jfieldID fid_index = env->GetFieldID(env->GetObjectClass(obj), "index", "I"); unsigned index = env->GetIntField(obj, fid_index); mutexBlackboard.Lock(); NMEA_INFO &basic = device_blackboard.SetRealState(index); basic.Connected.Update(fixed(MonotonicClockMS()) / 1000); BrokenDateTime date_time = BrokenDateTime::FromUnixTimeUTC(time / 1000); fixed second_of_day = fixed(date_time.GetSecondOfDay()) + /* add the millisecond fraction of the original timestamp for better accuracy */ fixed((unsigned)(time % 1000)) / 1000u; if (second_of_day < basic.Time && date_time > basic.DateTime) /* don't wrap around when going past midnight in UTC */ second_of_day += fixed(24u * 3600u); basic.Time = second_of_day; basic.DateTime = date_time; basic.gps.SatellitesUsed = n_satellites; basic.gps.real = true; basic.gps.AndroidInternalGPS = true; basic.Location = GeoPoint(Angle::degrees(fixed(longitude)), Angle::degrees(fixed(latitude))); if (n_satellites > 0) basic.LocationAvailable.Update(basic.Time); else basic.LocationAvailable.Clear(); if (hasAltitude) { fixed GeoidSeparation = LookupGeoidSeparation(basic.Location); basic.GPSAltitude = fixed(altitude) - GeoidSeparation; basic.GPSAltitudeAvailable.Update(basic.Time); } else basic.GPSAltitudeAvailable.Clear(); if (hasBearing) { basic.track = Angle::degrees(fixed(bearing)); basic.track_available.Update(basic.Time); } else basic.track_available.Clear(); if (hasSpeed) { basic.GroundSpeed = fixed(speed); basic.GroundSpeedAvailable.Update(basic.Time); } if (hasAccuracy) basic.gps.HDOP = fixed(accuracy); if (hasAcceleration) { // TODO: use ACCELERATION_STATE::complement() ?!? basic.acceleration.Available = true; basic.acceleration.Gload = fixed(acceleration); } device_blackboard.Merge(); mutexBlackboard.Unlock(); }
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; }