/** * Parse a "$VMVABD" sentence. * * Example: "$VMVABD,0000.0,M,0547.0,M,-0.0,,,MS,0.0,KH,22.4,C*65" */ static bool FlytecParseVMVABD(NMEAInputLine &line, NMEA_INFO &info) { fixed value; // 0,1 = GPS altitude, unit if (line.read_checked_compare(info.GPSAltitude, "M")) info.GPSAltitudeAvailable.Update(info.clock); // 2,3 = baro altitude, unit if (line.read_checked_compare(value, "M")) info.ProvideBaroAltitudeTrue(value); // 4-7 = integrated vario, unit line.skip(4); // 8,9 = indicated or true airspeed, unit if (line.read_checked_compare(value, "KH")) // XXX is that TAS or IAS? Documentation isn't clear. info.ProvideBothAirspeeds(Units::ToSysUnit(value, unKiloMeterPerHour)); // 10,11 = temperature, unit info.TemperatureAvailable = line.read_checked_compare(value, "C"); if (info.TemperatureAvailable) info.OutsideAirTemperature = Units::ToSysUnit(value, unGradCelcius); return true; }
/** * Parse a "$VMVABD" sentence. * * Example: "$VMVABD,0000.0,M,0547.0,M,-0.0,,,MS,0.0,KH,22.4,C*65" */ static bool FlytecParseVMVABD(NMEAInputLine &line, NMEA_INFO &info, bool enable_baro) { fixed value; // 0,1 = GPS altitude, unit line.read_checked_compare(info.GPSAltitude, "M"); // 2,3 = baro altitude, unit bool available = line.read_checked_compare(value, "M"); if (enable_baro) { if (available) info.BaroAltitude = value; info.BaroAltitudeAvailable = available; } // 4-7 = integrated vario, unit line.skip(4); // 8,9 = indicated or true airspeed, unit info.AirspeedAvailable = line.read_checked_compare(value, "KH"); if (info.AirspeedAvailable) { // XXX is that TAS or IAS? Documentation isn't clear. info.TrueAirspeed = Units::ToSysUnit(value, unKiloMeterPerHour); info.IndicatedAirspeed = info.TrueAirspeed; } // 10,11 = temperature, unit info.TemperatureAvailable = line.read_checked_compare(value, "C"); if (info.TemperatureAvailable) info.OutsideAirTemperature = Units::ToSysUnit(value, unGradCelcius); return true; }
static bool ParseAPENV1(NMEAInputLine &line, NMEAInfo &info) { // $APENV1,IAS,Altitude,0,0,0,VerticalSpeed, int ias; if (!line.ReadChecked(ias)) return false; int altitude; if (!line.ReadChecked(altitude)) return false; line.Skip(); line.Skip(); line.Skip(); // In ft/min, quality of this is limited, do not use for the time being int vs; if (!line.ReadChecked(vs)) return false; auto sys_alt = Units::ToSysUnit(fixed(altitude), Unit::FEET); info.ProvidePressureAltitude(sys_alt); info.ProvideIndicatedAirspeedWithAltitude(Units::ToSysUnit(fixed(ias), Unit::KNOTS), sys_alt); return true; }
static bool LXWP2(NMEAInputLine &line, NMEA_INFO *GPS_INFO) { /* * $LXWP2, * maccready value, (m/s) * ballast, (1.0 - 1.5) * bugs, (0 - 100%) * polar_a, * polar_b, * polar_c, * audio volume */ fixed value; // MacCready value if (line.read_checked(value)) GPS_INFO->settings.ProvideMacCready(value, GPS_INFO->Time); // Ballast line.skip(); /* if (line.read_checked(value)) GPS_INFO->ProvideBallast(value, GPS_INFO->Time); */ // Bugs if (line.read_checked(value)) GPS_INFO->settings.ProvideBugs((fixed(100) - value) / 100, GPS_INFO->Time); return true; }
static bool LXWP2(NMEAInputLine &line, NMEA_INFO *GPS_INFO) { /* * $LXWP2, * maccready value, (m/s) * ballast, (1.0 - 1.5) * bugs, (0 - 100%) * polar_a, * polar_b, * polar_c, * audio volume */ fixed value; // MacCready value if (line.read_checked(value)) GPS_INFO->MacCready = value; // Ballast line.skip(); /* if (line.read_checked(value)) GPS_INFO->Ballast = value; */ // Bugs if (line.read_checked(value)) GPS_INFO->Bugs = fixed(100) - value; return true; }
bool NMEAParser::GSA(NMEAInputLine &line, NMEAInfo &info) { /* * $--GSA,a,a,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x.x,x.x,x.x*hh * * Field Number: * 1) Selection mode * M=Manual, forced to operate in 2D or 3D * A=Automatic, 3D/2D * 2) Mode (1 = no fix, 2 = 2D fix, 3 = 3D fix) * 3) ID of 1st satellite used for fix * 4) ID of 2nd satellite used for fix * ... * 14) ID of 12th satellite used for fix * 15) PDOP * 16) HDOP * 17) VDOP * 18) checksum */ line.Skip(); if (line.Read(0) == 1) info.location_available.Clear(); // satellites are in items 4-15 of GSA string (4-15 is 1-indexed) for (unsigned i = 0; i < GPSState::MAXSATELLITES; i++) info.gps.satellite_ids[i] = line.Read(0); info.gps.satellite_ids_available.Update(info.clock); return true; }
/** * Parse the $PLXVS sentence (LXNav V7). * * $PLXVS,OAT,mode,voltage *CS<CR><LF> * * Example: $PLXVS,23.1,0,12.3,*CS<CR><LF> * * @see http://www.xcsoar.org/trac/raw-attachment/ticket/1666/V7%20dataport%20specification%201.97.pdf */ static bool PLXVS(NMEAInputLine &line, NMEAInfo &info) { fixed temperature; if (line.ReadChecked(temperature)) { info.temperature = CelsiusToKelvin(temperature); info.temperature_available = true; } int mode; info.switch_state.flight_mode = SwitchState::FlightMode::UNKNOWN; if (line.ReadChecked(mode)) { if (mode == 0) info.switch_state.flight_mode = SwitchState::FlightMode::CIRCLING; else if (mode == 1) info.switch_state.flight_mode = SwitchState::FlightMode::CRUISE; } fixed voltage; if (line.ReadChecked(voltage)) { info.voltage = voltage; info.voltage_available.Update(info.clock); } return true; }
static bool ParsePITV3(NMEAInputLine &line, NMEAInfo &info) { fixed value; // bank angle [degrees, positive right] if (line.ReadChecked(value)) { info.attitude.bank_angle_available.Update(info.clock); info.attitude.bank_angle = Angle::Degrees(value); } // pitch angle [degrees, positive up] if (line.ReadChecked(value)) { info.attitude.pitch_angle_available.Update(info.clock); info.attitude.pitch_angle = Angle::Degrees(value); } // heading [degrees] if (line.ReadChecked(value)) { info.attitude.heading_available.Update(info.clock); info.attitude.heading = Angle::Degrees(value); } // IAS [m/s] if (line.ReadChecked(value)) { info.ProvideIndicatedAirspeed(value); } // Load factor [g] if (line.ReadChecked(value)) { info.acceleration.ProvideGLoad(value, true); } return true; }
static bool ReadFixedAndChar(NMEAInputLine &line, fixed &d, char &ch) { bool success = line.ReadChecked(d); ch = line.ReadFirstChar(); return success; }
// $PDVDS,nx,nz,flap,stallratio,netto static bool PDVDS(NMEAInputLine &line, NMEAInfo &info) { fixed AccelX = line.read(fixed_zero); fixed AccelZ = line.read(fixed_zero); int mag = (int)hypot(AccelX, AccelZ); info.acceleration.ProvideGLoad(fixed(mag) / 100, true); /* double flap = line.read(0.0); */ line.skip(); info.stall_ratio = line.read(fixed_zero); info.stall_ratio_available.Update(info.clock); fixed value; if (line.read_checked(value)) info.ProvideNettoVario(value / 10); //hasVega = true; return true; }
static bool PTFRS(NMEAInputLine &line, NMEAInfo &info) { // $PTFRS,1,0,0,0,0,0,0,0,5,1,10,0,3,1338313437,0,0,0,,,2*4E // // $PTFRS,<sealed>,<downloadmode>,<event>,<neartp>,<sealing>,<baromode>, // <decllock>,<newrecavail>,<enl>,<rpm>,<interval>,<error>,<timbase>, // <time>,<secpower>,<secpowerint>,<usup>,<ulit>, // <chargerstate>,<antstate>*CS<CR><LF> line.Skip(8); unsigned enl; if (line.ReadChecked(enl)) { info.engine_noise_level = enl; info.engine_noise_level_available.Update(info.clock); } line.Skip(7); unsigned supply_voltage; if (line.ReadChecked(supply_voltage) && supply_voltage != 0) { info.voltage = fixed(supply_voltage) / 1000; info.voltage_available.Update(info.clock); } return true; }
/** * Parse a "$VMVABD" sentence. * * Example: "$VMVABD,0000.0,M,0547.0,M,-0.0,,,MS,0.0,KH,22.4,C*65" */ static bool FlytecParseVMVABD(NMEAInputLine &line, NMEAInfo &info) { fixed value; // 0,1 = GPS altitude, unit if (line.ReadCheckedCompare(info.gps_altitude, "M")) info.gps_altitude_available.Update(info.clock); // 2,3 = baro altitude, unit if (line.ReadCheckedCompare(value, "M")) info.ProvideBaroAltitudeTrue(value); // 4-7 = integrated vario, unit line.Skip(4); // 8,9 = indicated or true airspeed, unit if (line.ReadCheckedCompare(value, "KH")) // XXX is that TAS or IAS? Documentation isn't clear. info.ProvideBothAirspeeds(Units::ToSysUnit(value, Unit::KILOMETER_PER_HOUR)); // 10,11 = temperature, unit info.temperature_available = line.ReadCheckedCompare(value, "C"); if (info.temperature_available) info.temperature = CelsiusToKelvin(value); return true; }
static bool LXWP2(NMEAInputLine &line, NMEAInfo &info) { /* * $LXWP2, * maccready value, (m/s) * ballast, (1.0 - 1.5) * bugs, (0 - 100%) * polar_a, * polar_b, * polar_c, * audio volume */ fixed value; // MacCready value if (line.ReadChecked(value)) info.settings.ProvideMacCready(value, info.clock); // Ballast if (line.ReadChecked(value)) info.settings.ProvideBallastOverload(value, info.clock); // Bugs if (line.ReadChecked(value)) info.settings.ProvideBugs((fixed(100) - value) / 100, info.clock); return true; }
/** * Parses a GLL sentence * * $--GLL,llll.ll,a,yyyyy.yy,a,hhmmss.ss,a,m,*hh * * Field Number: * 1) Latitude * 2) N or S (North or South) * 3) Longitude * 4) E or W (East or West) * 5) Universal Time Coordinated (UTC) * 6) Status A - Data Valid, V - Data Invalid * 7) FAA mode indicator (NMEA 2.3 and later) * 8) Checksum * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param info NMEA_INFO struct to parse into * @return Parsing success */ bool NMEAParser::GLL(NMEAInputLine &line, NMEAInfo &info) { GeoPoint location; bool valid_location = ReadGeoPoint(line, location); fixed ThisTime = TimeModify(line.read(fixed_zero), info.date_time_utc, info.date_available); ThisTime = TimeAdvanceTolerance(ThisTime); bool gpsValid = !NAVWarn(line.read_first_char()); if (!TimeHasAdvanced(ThisTime, info)) return true; if (!gpsValid) info.location_available.Clear(); else if (valid_location) info.location_available.Update(info.clock); if (valid_location) info.location = location; info.gps.real = real; #ifdef ANDROID info.gps.android_internal_gps = false; #endif return true; }
// RMN: Volkslogger // Source data: // $PGCS,1,0EC0,FFF9,0C6E,02*61 // $PGCS,1,0EC0,FFFA,0C6E,03*18 static bool vl_PGCS1(NMEAInputLine &line, NMEAInfo &info) { if (line.Read(1) != 1) return false; /* pressure sensor */ line.Skip(); // four characers, hex, barometric altitude unsigned u_altitude; if (line.ReadHexChecked(u_altitude)) { int altitude(u_altitude); if (altitude > 60000) /* Assuming that altitude has wrapped around. 60 000 m occurs at QNH ~2000 hPa */ altitude -= 65535; info.ProvidePressureAltitude(fixed(altitude)); } // ExtractParameter(String,ctemp,3); // four characters, hex, constant. Value 1371 (dec) // nSatellites = (int)(min(12,HexStrToDouble(ctemp, NULL))); return false; }
/** * Parses a PFLAU sentence * (Operating status and priority intruder and obstacle data) * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param GPS_INFO GPS_INFO struct to parse into * @return Parsing success * @see http://flarm.com/support/manual/FLARM_DataportManual_v4.06E.pdf */ bool NMEAParser::PFLAU(NMEAInputLine &line, FLARM_STATE &flarm) { static int old_flarm_rx = 0; flarm.FLARM_Available = true; isFlarm = true; // PFLAU,<RX>,<TX>,<GPS>,<Power>,<AlarmLevel>,<RelativeBearing>,<AlarmType>, // <RelativeVertical>,<RelativeDistance>(,<ID>) flarm.FLARM_RX = line.read(0); flarm.FLARM_TX = line.read(0); flarm.FLARM_GPS = line.read(0); line.skip(); flarm.FLARM_AlarmLevel = line.read(0); // process flarm updates if (flarm.FLARM_RX && old_flarm_rx == 0) // traffic has appeared.. InputEvents::processGlideComputer(GCE_FLARM_TRAFFIC); if (flarm.FLARM_RX == 0 && old_flarm_rx) // traffic has disappeared.. InputEvents::processGlideComputer(GCE_FLARM_NOTRAFFIC); // TODO feature: add another event for new traffic. old_flarm_rx = flarm.FLARM_RX; return false; }
bool VegaDevice::PDVSC(NMEAInputLine &line, gcc_unused NMEAInfo &info) { char responsetype[10]; line.Read(responsetype, 10); char name[80]; line.Read(name, 80); if (StringIsEqual(name, "ERROR")) // ignore error responses... return true; int value = line.Read(0); if (StringIsEqual(name, "ToneDeadbandCruiseLow")) value = std::max(value, -value); if (StringIsEqual(name, "ToneDeadbandCirclingLow")) value = std::max(value, -value); settings.Lock(); settings.Set(name, value); settings.Unlock(); return true; }
/** * Parses a GLL sentence * * $--GLL,llll.ll,a,yyyyy.yy,a,hhmmss.ss,a,m,*hh * * Field Number: * 1) Latitude * 2) N or S (North or South) * 3) Longitude * 4) E or W (East or West) * 5) Universal Time Coordinated (UTC) * 6) Status A - Data Valid, V - Data Invalid * 7) FAA mode indicator (NMEA 2.3 and later) * 8) Checksum * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param GPS_INFO GPS_INFO struct to parse into * @return Parsing success */ bool NMEAParser::GLL(NMEAInputLine &line, NMEA_INFO *GPS_INFO) { GeoPoint location; bool valid_location = ReadGeoPoint(line, location); fixed ThisTime = TimeModify(line.read(fixed_zero), GPS_INFO->DateTime); gpsValid = !NAVWarn(line.read_first_char()); if (!activeGPS) return true; if (GPS_INFO->gps.Replay) // block actual GPS signal return true; GPS_INFO->gps.NAVWarning = !gpsValid; if (!TimeHasAdvanced(ThisTime, GPS_INFO)) return false; if (valid_location) GPS_INFO->Location = location; else GPS_INFO->gps.NAVWarning = true; return true; }
bool VegaDevice::PDVSC(NMEAInputLine &line, gcc_unused NMEAInfo &info) { char responsetype[10]; line.read(responsetype, 10); char name[80]; line.read(name, 80); if (strcmp(name, "ERROR") == 0) // ignore error responses... return true; int value = line.read(0); if (strcmp(name, "ToneDeadbandCruiseLow") == 0) value = std::max(value, -value); if (strcmp(name, "ToneDeadbandCirclingLow") == 0) value = std::max(value, -value); settings_mutex.Lock(); settings[name] = value; settings_mutex.Unlock(); return true; }
/** * Parses a RMC sentence * * $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a,m,*hh * * Field Number: * 1) UTC Time * 2) Status, V=Navigation receiver warning A=Valid * 3) Latitude * 4) N or S * 5) Longitude * 6) E or W * 7) Speed over ground, knots * 8) Track made good, degrees true * 9) Date, ddmmyy * 10) Magnetic Variation, degrees * 11) E or W * 12) FAA mode indicator (NMEA 2.3 and later) * 13) Checksum * @param String Input string * @param params Parameter array * @param nparams Number of parameters * @param info NMEA_INFO struct to parse into * @return Parsing success */ bool NMEAParser::RMC(NMEAInputLine &line, NMEAInfo &info) { fixed ThisTime = line.read(fixed_zero); bool gpsValid = !NAVWarn(line.read_first_char()); GeoPoint location; bool valid_location = ReadGeoPoint(line, location); GPSState &gps = info.gps; fixed speed; bool GroundSpeedAvailable = line.read_checked(speed); fixed track; bool track_available = line.read_checked(track); // JMW get date info first so TimeModify is accurate if (ReadDate(line, info.date_time_utc)) info.date_available = true; ThisTime = TimeModify(ThisTime, info.date_time_utc, info.date_available); ThisTime = TimeAdvanceTolerance(ThisTime); if (!TimeHasAdvanced(ThisTime, info)) return true; if (!gpsValid) info.location_available.Clear(); else if (valid_location) info.location_available.Update(info.clock); if (valid_location) info.location = location; if (GroundSpeedAvailable) { info.ground_speed = Units::ToSysUnit(speed, unKnots); info.ground_speed_available.Update(info.clock); } if (track_available && info.MovementDetected()) { // JMW don't update bearing unless we're moving info.track = Angle::degrees(track).as_bearing(); info.track_available.Update(info.clock); } if (!GGAAvailable) { // update SatInUse, some GPS receiver don't emit GGA sentence gps.satellites_used = -1; } info.gps.real = real; #ifdef ANDROID info.gps.android_internal_gps = false; #endif return true; }
bool OpenVarioDevice::POV(NMEAInputLine &line, NMEAInfo &info) { /* * Type definitions: * * E: TE vario in m/s * P: static pressure in hPa * Q: dynamic pressure in Pa * R: total pressure in hPa * S: true airspeed in km/h * T: temperature in deg C */ while (!line.IsEmpty()) { char type = line.ReadOneChar(); if (type == '\0') break; fixed value; if (!line.ReadChecked(value)) break; switch (type) { case 'E': { info.ProvideTotalEnergyVario(value); break; } case 'P': { AtmosphericPressure pressure = AtmosphericPressure::HectoPascal(value); info.ProvideStaticPressure(pressure); break; } case 'Q': { AtmosphericPressure pressure = AtmosphericPressure::Pascal(value); info.ProvideDynamicPressure(pressure); break; } case 'R': { AtmosphericPressure pressure = AtmosphericPressure::HectoPascal(value); info.ProvidePitotPressure(pressure); break; } case 'S': { value = Units::ToSysUnit(value, Unit::KILOMETER_PER_HOUR); info.ProvideTrueAirspeed(value); break; } case 'T': { info.temperature = CelsiusToKelvin(value); info.temperature_available = true; break; } } } return true; }
static bool GPWIN(NMEAInputLine &line, NMEAInfo &info) { line.skip(2); fixed value; if (line.read_checked(value)) info.ProvidePressureAltitude(value / 10); return false; }
static bool GPWIN(NMEAInputLine &line, NMEA_INFO *GPS_INFO) { line.skip(2); fixed value; if (line.read_checked(value)) GPS_INFO->ProvidePressureAltitude(value / 10); return false; }
static bool PDAAV(NMEAInputLine &line, gcc_unused NMEAInfo &info) { gcc_unused unsigned short beepfrequency = line.Read(0); gcc_unused unsigned short soundfrequency = line.Read(0); gcc_unused unsigned char soundtype = line.Read(0); // Temporarily commented out - function as yet undefined // audio_setconfig(beepfrequency, soundfrequency, soundtype); return true; }
static bool PDVVT(NMEAInputLine &line, NMEAInfo &info) { int value; info.temperature_available = line.ReadChecked(value); if (info.temperature_available) info.temperature = fixed(value) / 10; info.humidity_available = line.ReadChecked(info.humidity); return true; }
static bool GPWIN(NMEAInputLine &line, NMEA_INFO *GPS_INFO, bool enable_baro) { line.skip(2); fixed value; if (enable_baro && line.read_checked(value)) { GPS_INFO->BaroAltitude = GPS_INFO->pressure.AltitudeToQNHAltitude(value / 10); GPS_INFO->BaroAltitudeAvailable = true; } return false; }
void PDVSC_S(NMEAInputLine &line) { char name[64], value[256]; line.read(name, ARRAY_SIZE(name)); line.read(value, ARRAY_SIZE(value)); settings[name] = value; ConsoleOperationEnvironment env; char buffer[512]; snprintf(buffer, ARRAY_SIZE(buffer), "PDVSC,A,%s,%s", name, value); PortWriteNMEA(*port, buffer, env); }
static bool PZAN2(NMEAInputLine &line, NMEAInfo &info) { fixed vtas, wnet; if (line.ReadChecked(vtas)) info.ProvideTrueAirspeed(Units::ToSysUnit(vtas, Unit::KILOMETER_PER_HOUR)); if (line.ReadChecked(wnet)) info.ProvideTotalEnergyVario((wnet - fixed(10000)) / 100); return true; }
static bool PZAN2(NMEAInputLine &line, NMEAInfo &info) { fixed vtas, wnet; if (line.read_checked(vtas)) info.ProvideTrueAirspeed(Units::ToSysUnit(vtas, unKiloMeterPerHour)); if (line.read_checked(wnet)) info.ProvideTotalEnergyVario((wnet - fixed(10000)) / 100); return true; }
static bool PDSWC(NMEAInputLine &line, NMEAInfo &info, Vega::VolatileData &volatile_data) { unsigned value; if (line.ReadChecked(value) && info.settings.ProvideMacCready(fixed(value) / 10, info.clock)) volatile_data.mc = value; auto &switches = info.switch_state; auto &vs = switches.vega; vs.inputs = line.ReadHex(0); vs.outputs = line.ReadHex(0); if (vs.GetFlapLanding()) switches.flap_position = SwitchState::FlapPosition::LANDING; else if (vs.GetFlapZero()) switches.flap_position = SwitchState::FlapPosition::NEUTRAL; else if (vs.GetFlapNegative()) switches.flap_position = SwitchState::FlapPosition::NEGATIVE; else if (vs.GetFlapPositive()) switches.flap_position = SwitchState::FlapPosition::POSITIVE; else switches.flap_position = SwitchState::FlapPosition::UNKNOWN; if (vs.GetUserSwitchMiddle()) switches.user_switch = SwitchState::UserSwitch::MIDDLE; else if (vs.GetUserSwitchUp()) switches.user_switch = SwitchState::UserSwitch::UP; else if (vs.GetUserSwitchDown()) switches.user_switch = SwitchState::UserSwitch::DOWN; else switches.user_switch = SwitchState::UserSwitch::UNKNOWN; if (vs.GetAirbrakeLocked()) switches.airbrake_state = SwitchState::AirbrakeState::LOCKED; else if (vs.GetAirbrakeNotLocked()) switches.airbrake_state = SwitchState::AirbrakeState::NOT_LOCKED; else switches.airbrake_state = SwitchState::AirbrakeState::UNKNOWN; switches.flight_mode = vs.GetCircling() ? SwitchState::FlightMode::CIRCLING : SwitchState::FlightMode::CRUISE; if (line.ReadChecked(value)) { info.voltage = fixed(value) / 10; info.voltage_available.Update(info.clock); } return true; }