/** * $PWES1,DD,MM,S,AAA,F,V,LLL,BB*CS<CR><LF> */ static bool PWES1(NMEAInputLine &line, NMEAInfo &info) { line.Skip(); /* device */ int i; if (line.ReadChecked(i)) info.settings.ProvideMacCready(fixed(i) / 10, info.clock); info.switch_state.flight_mode = SwitchState::FlightMode::UNKNOWN; if (line.ReadChecked(i)) { if (i == 0) info.switch_state.flight_mode = SwitchState::FlightMode::CIRCLING; else if (i == 1) info.switch_state.flight_mode = SwitchState::FlightMode::CRUISE; } line.Skip(3); if (line.ReadChecked(i)) info.settings.ProvideWingLoading(fixed(i) / 10, info.clock); if (line.ReadChecked(i)) info.settings.ProvideBugs(fixed(100 - i) / 100, 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 PZAN3(NMEAInputLine &line, NMEAInfo &info) { // old: $PZAN3,+,026,V,321,035,A,321,035,V*cc // new: $PZAN3,+,026,A,321,035,V[,A]*cc line.Skip(3); int direction, speed; if (!line.ReadChecked(direction) || !line.ReadChecked(speed)) return false; char okay = line.ReadFirstChar(); if (okay == 'V') { okay = line.ReadFirstChar(); if (okay == 'V') return true; if (okay != 'A') { line.Skip(); okay = line.ReadFirstChar(); } } if (okay == 'A') { SpeedVector wind(Angle::Degrees(direction), Units::ToSysUnit(fixed(speed), Unit::KILOMETER_PER_HOUR)); info.ProvideExternalWind(wind); } 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; }
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; }
/** * $PWES1,DD,MM,S,AAA,F,V,LLL,BB*CS<CR><LF> */ static bool PWES1(NMEAInputLine &line, NMEAInfo &info) { line.Skip(); /* device */ int i; if (line.ReadChecked(i)) info.settings.ProvideMacCready(fixed(i) / 10, info.clock); if (line.ReadChecked(i)) { if (i == 0) { info.switch_state.flight_mode = SwitchInfo::FlightMode::CIRCLING; info.switch_state.speed_command = false; info.switch_state_available = true; } else if (i == 1) { info.switch_state.flight_mode = SwitchInfo::FlightMode::CRUISE; info.switch_state.speed_command = true; info.switch_state_available = true; } } line.Skip(3); if (line.ReadChecked(i)) info.settings.ProvideWingLoading(fixed(i) / 10, info.clock); if (line.ReadChecked(i)) info.settings.ProvideBugs(fixed(100 - i) / 100, info.clock); 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; }
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 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 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 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; }
static bool ReadSpeedVector(NMEAInputLine &line, SpeedVector &value_r) { double norm, bearing; bool norm_valid = line.ReadChecked(norm); bool bearing_valid = line.ReadChecked(bearing); if (bearing_valid && norm_valid) { value_r.norm = Units::ToSysUnit(norm, Unit::KILOMETER_PER_HOUR); value_r.bearing = Angle::Degrees(bearing); return true; } else return false; }
static bool LXWP3(NMEAInputLine &line, NMEAInfo &info) { /* * $LXWP3, * altioffset * scmode * variofil * tefilter * televel * varioavg * variorange * sctab * sclow * scspeed * SmartDiff * glider name * time offset */ fixed value; // Altitude offset -> QNH if (line.ReadChecked(value)) { value = Units::ToSysUnit(-value, Unit::FEET); auto qnh = AtmosphericPressure::PressureAltitudeToStaticPressure(value); info.settings.ProvideQNH(qnh, info.clock); } return true; }
bool NMEAParser::ReadTime(NMEAInputLine &line, BrokenTime &broken_time, fixed &time_of_day_s) { fixed value; if (!line.ReadChecked(value)) return false; // Calculate Hour auto hours = value / 10000; broken_time.hour = (int)hours; // Calculate Minute auto mins = value / 100; mins = mins - fixed(broken_time.hour) * 100; broken_time.minute = (int)mins; // Calculate Second auto secs = value - fixed(broken_time.hour * 10000 + broken_time.minute * 100); broken_time.second = (int)secs; time_of_day_s = secs + fixed(broken_time.minute * 60 + broken_time.hour * 3600); return true; }
// $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); fixed mag = SmallHypot(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.ReadChecked(value)) info.ProvideNettoVario(value / 10); //hasVega = true; return true; }
static bool ReadFixedAndChar(NMEAInputLine &line, fixed &d, char &ch) { bool success = line.ReadChecked(d); ch = line.ReadFirstChar(); return success; }
static bool LXWP0(NMEAInputLine &line, NMEAInfo &info) { /* $LXWP0,Y,222.3,1665.5,1.71,,,,,,239,174,10.1 0 loger_stored (Y/N) 1 IAS (kph) ----> Condor uses TAS! 2 baroaltitude (m) 3-8 vario (m/s) (last 6 measurements in last second) 9 heading of plane 10 windcourse (deg) 11 windspeed (kph) */ line.Skip(); fixed airspeed; bool tas_available = line.ReadChecked(airspeed); if (tas_available && (airspeed < fixed(-50) || airspeed > fixed(250))) /* implausible */ return false; fixed value; if (line.ReadChecked(value)) /* a dump on a LX7007 has confirmed that the LX sends uncorrected altitude above 1013.25hPa here */ info.ProvidePressureAltitude(value); if (tas_available) /* * Call ProvideTrueAirspeed() after ProvidePressureAltitude() to use * the provided altitude (if available) */ info.ProvideTrueAirspeed(Units::ToSysUnit(airspeed, Unit::KILOMETER_PER_HOUR)); if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value); line.Skip(6); SpeedVector wind; if (ReadSpeedVector(line, wind)) info.ProvideExternalWind(wind); return true; }
/** * Parse a "$D" sentence. * * Example: "$D,+0,100554,+25,18,+31,,0,-356,+25,+11,115,96*6A" */ static bool LeonardoParseD(NMEAInputLine &line, NMEAInfo &info) { double value; // 0 = vario [dm/s] if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value / 10); if (line.Rest().empty()) /* short "$D" sentence ends after vario */ return true; // 1 = air pressure [Pa] if (line.ReadChecked(value)) info.ProvideStaticPressure(AtmosphericPressure::Pascal(value)); // 2 = netto vario [dm/s] if (line.ReadChecked(value)) info.ProvideNettoVario(value / 10); // 3 = airspeed [km/h] /* XXX is that TAS or IAS? */ if (line.ReadChecked(value)) info.ProvideTrueAirspeed(Units::ToSysUnit(value, Unit::KILOMETER_PER_HOUR)); // 4 = temperature [deg C] double oat; info.temperature_available = line.ReadChecked(oat); if (info.temperature_available) info.temperature = CelsiusToKelvin(oat); // 5 = compass [degrees] /* XXX unsupported by XCSoar */ // 6 = optimal speed [km/h] /* XXX unsupported by XCSoar */ // 7 = equivalent MacCready [cm/s] /* XXX unsupported by XCSoar */ // 8 = wind speed [km/h] /* not used here, the "$C" record repeats it together with the direction */ 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; }
bool NMEAParser::PTAS1(NMEAInputLine &line, NMEAInfo &info) { /* * $PTAS1,xxx,yyy,zzzzz,aaa*CS<CR><LF> * * xxx * CV or current vario. =vario*10+200 range 0-400(display +/-20.0 knots) * * yyy * AV or average vario. =vario*10+200 range 0-400(display +/-20.0 knots) * * zzzzz * Barometric altitude in feet +2000 * * aaa * TAS knots 0-200 */ // Parse current vario data fixed vario; if (line.ReadChecked(vario)) { // Properly convert to m/s vario = Units::ToSysUnit((vario - fixed(200)) / 10, Unit::KNOTS); info.ProvideTotalEnergyVario(vario); } // Skip average vario data line.Skip(); // Parse barometric altitude fixed baro_altitude; if (line.ReadChecked(baro_altitude)) { // Properly convert to meter baro_altitude = Units::ToSysUnit(baro_altitude - fixed(2000), Unit::FEET); info.ProvidePressureAltitude(baro_altitude); } // Parse true airspeed fixed vtas; if (line.ReadChecked(vtas)) info.ProvideTrueAirspeed(Units::ToSysUnit(vtas, Unit::KNOTS)); return true; }
static bool cLXWP0(NMEAInputLine &line, NMEAInfo &info) { /* $LXWP0,Y,222.3,1665.5,1.71,,,,,,239,174,10.1 0 logger_stored (Y/N) 1 IAS (kph) ----> Condor uses TAS! 2 baroaltitude (m) 3 vario (m/s) 4-8 unknown 9 heading of plane 10 windcourse (deg) 11 windspeed (kph) */ fixed value; line.Skip(); fixed airspeed; bool tas_available = line.ReadChecked(airspeed); fixed alt = line.Read(fixed_zero); if (tas_available) info.ProvideTrueAirspeedWithAltitude(Units::ToSysUnit(airspeed, Unit::KILOMETER_PER_HOUR), alt); // ToDo check if QNH correction is needed! info.ProvideBaroAltitudeTrue(alt); if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value); line.Skip(6); SpeedVector wind; if (ReadSpeedVector(line, wind)) info.ProvideExternalWind(wind); return true; }
static bool ReadSpeedVector(NMEAInputLine &line, SpeedVector &value_r) { fixed bearing, norm; bool bearing_valid = line.ReadChecked(bearing); bool norm_valid = line.ReadChecked(norm); if (bearing_valid && norm_valid) { // Condor 1.1.4 outputs the direction that the wind is going to, // _not_ the direction it is coming from !! // // This seems to differ from the output that the LX devices are giving !! value_r.bearing = Angle::Degrees(bearing).Reciprocal(); value_r.norm = Units::ToSysUnit(norm, Unit::KILOMETER_PER_HOUR); return true; } else return false; }
/** * Parse a "$C" sentence. * * Example: "$C,+2025,-7,+18,+25,+29,122,314,314,0,-356,+25,45,T*3D" */ static bool LeonardoParseC(NMEAInputLine &line, NMEAInfo &info) { double value; // 0 = altitude [m] if (line.ReadChecked(value)) info.ProvideBaroAltitudeTrue(value); // 1 = vario [cm/s] if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value / 100); // 2 = airspeed [km/h] /* XXX is that TAS or IAS? */ if (line.ReadChecked(value)) info.ProvideTrueAirspeed(Units::ToSysUnit(value, Unit::KILOMETER_PER_HOUR)); if (line.Rest().empty()) /* short "$C" sentence ends after airspeed */ return true; // 3 = netto vario [dm/s] if (line.ReadChecked(value)) info.ProvideNettoVario(value / 10); // 4 = temperature [deg C] double oat; info.temperature_available = line.ReadChecked(oat); if (info.temperature_available) info.temperature = CelsiusToKelvin(oat); line.Skip(5); // 10 = wind speed [km/h] // 11 = wind direction [degrees] SpeedVector wind; if (ReadSpeedVector(line, wind)) info.ProvideExternalWind(wind); return true; }
static bool ParsePITV4(NMEAInputLine &line, NMEAInfo &info) { fixed value; // TE vario [m/s] if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value); return true; }
static bool PDVDV(NMEAInputLine &line, NMEAInfo &info) { fixed value; if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value / 10); bool ias_available = line.ReadChecked(value); fixed tas_ratio = line.Read(fixed(1024)) / 1024; if (ias_available) info.ProvideBothAirspeeds(value / 10, value / 10 * tas_ratio); //hasVega = true; if (line.ReadChecked(value)) info.ProvidePressureAltitude(value); return true; }
static bool PZAN4(NMEAInputLine &line, NMEAInfo &info) { // $PZAN4,1.5,+,20,39,45*cc fixed mc; if (line.ReadChecked(mc)) info.settings.ProvideMacCready(mc, info.clock); return true; }
static bool GPWIN(NMEAInputLine &line, NMEAInfo &info) { line.Skip(2); fixed value; if (line.ReadChecked(value)) info.ProvidePressureAltitude(value / 10); return false; }
/** * Parse a "$PDGFTL1" sentence. * * Example: "$PDGFTL1,2025,2000,250,-14,45,134,28,65,382,153*3D" */ static bool PDGFTL1(NMEAInputLine &line, NMEAInfo &info) { fixed value; // Baro Altitude QNE(1013.25) 2025 meter 2025 mt if (line.ReadChecked(value)) info.ProvidePressureAltitude(value); // Baro Altitude QNH 2000 meter 2000 mt if (line.ReadChecked(value)) info.ProvideBaroAltitudeTrue(value); // Vario 250 cm/sec +2,50 m/s if (line.ReadChecked(value)) info.ProvideTotalEnergyVario(value / 100); // Netto Vario -14 dm/sec -1,40 m/s if (line.ReadChecked(value)) info.ProvideNettoVario(value / 10); // Indicated Air Speed 45 km/h 45 km/h // Ground Efficiency 134 ratio 13,4 : 1 line.Skip(2); // Wind Speed 28 km/h 28 km/h // Wind Direction 65 degree 65 degree SpeedVector wind; if (ReadSpeedVector(line, wind)) info.ProvideExternalWind(wind); // Main Lithium Battery Voltage 382 0.01 volts 3,82 volts if (line.ReadChecked(value)) { info.voltage = value / 100; info.voltage_available.Update(info.clock); } // Backup AA Battery Voltage 153 0.01 volts 1,53 volts 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)) { if (value <= fixed(1.5) && value >= fixed(1.0)) // LX160 (sw 3.04) reports bugs as 1.00, 1.05 or 1.10 (#2167) info.settings.ProvideBugs(fixed(2) - value, info.clock); else // All other known LX devices report bugs as 0, 5, 10, 15, ... info.settings.ProvideBugs((fixed(100) - value) / 100, info.clock); } line.Skip(3); unsigned volume; if (line.ReadChecked(volume)) info.settings.ProvideVolume(volume, info.clock); return true; }
static bool PZAN1(NMEAInputLine &line, NMEAInfo &info) { fixed baro_altitude; if (line.ReadChecked(baro_altitude)) /* the ZS1 documentation does not specify wheter the altitude is STD or QNH, but Franz Poeschl confirmed via email that it is the QNH altitude */ info.ProvideBaroAltitudeTrue(baro_altitude); return true; }