Пример #1
0
/**
 * 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;
}
Пример #2
0
static void
Run(IGCWriter &writer)
{
  static const GeoPoint home(Angle::Degrees(fixed(7.7061111111111114)),
                             Angle::Degrees(fixed(51.051944444444445)));
  static const GeoPoint tp(Angle::Degrees(fixed(10.726111111111111)),
                           Angle::Degrees(fixed(50.6322)));

  static NMEAInfo i;
  i.clock = fixed_one;
  i.time = fixed(1);
  i.time_available.Update(i.clock);
  i.date_time_utc.year = 2010;
  i.date_time_utc.month = 9;
  i.date_time_utc.day = 4;
  i.date_time_utc.hour = 11;
  i.date_time_utc.minute = 22;
  i.date_time_utc.second = 33;
  i.location = home;
  i.location_available.Update(i.clock);
  i.gps_altitude = fixed(487);
  i.gps_altitude_available.Update(i.clock);
  i.ProvidePressureAltitude(fixed(490));
  i.ProvideBaroAltitudeTrue(fixed(400));

  writer.WriteHeader(i.date_time_utc, _T("Pilot Name"), _T("ASK-21"),
                     _T("D-1234"), _T("34"), "FOO", _T("bar"), false);
  writer.StartDeclaration(i.date_time_utc, 3);
  writer.AddDeclaration(home, _T("Bergneustadt"));
  writer.AddDeclaration(tp, _T("Suhl"));
  writer.AddDeclaration(home, _T("Bergneustadt"));
  writer.EndDeclaration();

  writer.LogEmptyFRecord(i.date_time_utc);

  i.date_time_utc.second += 5;
  writer.LogPoint(i);
  i.date_time_utc.second += 5;
  writer.LogEvent(i, "my_event");
  i.date_time_utc.second += 5;
  writer.LoggerNote(_T("my_note"));

  int satellites[GPSState::MAXSATELLITES];
  for (unsigned i = 0; i < GPSState::MAXSATELLITES; ++i)
    satellites[i] = 0;

  satellites[2] = 12;
  satellites[4] = 17;
  satellites[7] = 1;

  i.date_time_utc.second += 5;
  writer.LogFRecord(i.date_time_utc, satellites);

  i.location = GeoPoint(Angle::Degrees(fixed(-7.7061111111111114)),
                        Angle::Degrees(fixed(-51.051944444444445)));
  writer.LogPoint(i);

  writer.Flush();
  writer.Sign();
}
Пример #3
0
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;
}
Пример #4
0
/**
 * $PWES0,DD,VVVV,MMMM,NNNN,BBBB,SSSS,AAAAA,QQQQQ,IIII,TTTT,UUU,CCCC*CS<CR><LF>
 */
static bool
PWES0(NMEAInputLine &line, NMEAInfo &info)
{
  int i;

  line.Skip(); /* device */

  if (line.ReadChecked(i) && i >= -999 && i <= 999)
    info.ProvideTotalEnergyVario(fixed(i) / 10);

  line.Skip(); /* average vario */

  if (line.ReadChecked(i) && i >= -999 && i <= 999)
    info.ProvideNettoVario(fixed(i) / 10);

  line.Skip(); /* average netto vario */
  line.Skip(); /* speed to fly */

  unsigned altitude;
  if (line.ReadChecked(altitude) && altitude <= 99999)
    info.ProvidePressureAltitude(fixed(altitude));

  if (line.ReadChecked(altitude) && altitude <= 99999)
    info.ProvideBaroAltitudeTrue(fixed(altitude));

  unsigned ias, tas;
  bool have_ias = line.ReadChecked(ias) && ias <= 9999;
  bool have_tas = line.ReadChecked(tas) && tas <= 9999;
  if (have_ias && have_tas)
    info.ProvideBothAirspeeds(Units::ToSysUnit(fixed(ias) / 10,
                                               Unit::KILOMETER_PER_HOUR),
                              Units::ToSysUnit(fixed(tas) / 10,
                                               Unit::KILOMETER_PER_HOUR));

  else if (!have_ias && have_tas)
    info.ProvideTrueAirspeed(Units::ToSysUnit(fixed(tas) / 10,
                                              Unit::KILOMETER_PER_HOUR));

  unsigned voltage;
  if (line.ReadChecked(voltage) && voltage <= 999) {
    info.voltage = fixed(voltage) / 10;
    info.voltage_available.Update(info.clock);
  }

  if (line.ReadChecked(i) && i >= -999 && i <= 999) {
    info.temperature = CelsiusToKelvin(fixed(i) / 10);
    info.temperature_available = true;
  }

  return true;
}
Пример #5
0
/**
 * $PWES0,DD,VVVV,MMMM,NNNN,BBBB,SSSS,AAAAA,QQQQQ,IIII,TTTT,UUU,CCCC*CS<CR><LF>
 */
static bool
PWES0(NMEAInputLine &line, NMEAInfo &info)
{
  int i, k;

  line.skip(); /* device */

  if (line.read_checked(i))
    info.ProvideTotalEnergyVario(fixed(i) / 10);

  line.skip(); /* average vario */

  if (line.read_checked(i))
    info.ProvideNettoVario(fixed(i) / 10);

  line.skip(); /* average netto vario */
  line.skip(); /* speed to fly */

  if (line.read_checked(i))
    info.ProvidePressureAltitude(fixed(i));

  if (line.read_checked(i))
    info.ProvideBaroAltitudeTrue(fixed(i));

  bool have_ias = line.read_checked(i);
  bool have_tas = line.read_checked(k);
  if (have_ias && have_tas)
    info.ProvideBothAirspeeds(Units::ToSysUnit(fixed(i) / 10,
                                               Unit::KILOMETER_PER_HOUR),
                              Units::ToSysUnit(fixed(k) / 10,
                                               Unit::KILOMETER_PER_HOUR));

  else if (!have_ias && have_tas)
    info.ProvideTrueAirspeed(Units::ToSysUnit(fixed(k) / 10,
                                              Unit::KILOMETER_PER_HOUR));

  if (line.read_checked(i)) {
    info.voltage = fixed(i) / 10;
    info.voltage_available.Update(info.clock);
  }

  if (line.read_checked(i)) {
    info.temperature = CelsiusToKelvin(fixed(i) / 10);
    info.temperature_available = true;
  }

  return true;
}
Пример #6
0
/**
 * Parse a "$PDGFTL1" sentence.
 *
 * Example: "$PDGFTL1,2025,2000,250,-14,45,134,28,65,382,153*3D"
 */
static bool
PDGFTL1(NMEAInputLine &line, NMEAInfo &info)
{
  double 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
  if (line.ReadChecked(value))
    info.ProvideIndicatedAirspeed(Units::ToSysUnit(value, Unit::KILOMETER_PER_HOUR));

  //  Ground Efficiency  134      ratio        13,4 : 1
  line.Skip();

  //  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;
}
Пример #7
0
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;
}
Пример #8
0
/**
 * $PWES0,DD,VVVV,MMMM,NNNN,BBBB,SSSS,AAAAA,QQQQQ,IIII,TTTT,UUU,CCC*CS<CR><LF>
 */
static bool
PWES0(NMEAInputLine &line, NMEAInfo &info)
{
    int i, k;

    line.skip(); /* device */

    if (line.read_checked(i))
        info.ProvideTotalEnergyVario(fixed(i) / 10);

    line.skip(); /* average vario */

    if (line.read_checked(i))
        info.ProvideNettoVario(fixed(i) / 10);

    line.skip(); /* average netto vario */
    line.skip(); /* speed to fly */

    if (line.read_checked(i))
        info.ProvidePressureAltitude(fixed(i));

    if (line.read_checked(i))
        info.ProvideBaroAltitudeTrue(fixed(i));

    bool have_ias = line.read_checked(i);
    bool have_tas = line.read_checked(k);
    if (have_ias && have_tas)
        info.ProvideBothAirspeeds(Units::ToSysUnit(fixed(i) / 10,
                                  unKiloMeterPerHour),
                                  Units::ToSysUnit(fixed(k) / 10,
                                          unKiloMeterPerHour));

    if (line.read_checked(i)) {
        info.voltage = fixed(i) / 10;
        info.voltage_available.Update(info.clock);
    }

    if (line.read_checked(i)) {
        info.temperature = Units::ToSysUnit(fixed(i) / 10, unGradCelcius);
        info.temperature_available = true;
    }

    return true;
}
Пример #9
0
/**
 * 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;
}
Пример #10
0
/**
 * Parses a PGRMZ sentence (Garmin proprietary).
 *
 * @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::RMZ(NMEAInputLine &line, NMEAInfo &info)
{
  //JMW?  RMZAltitude = info.pressure.PressureAltitudeToQNHAltitude(RMZAltitude);

  fixed value;
  if (ReadAltitude(line, value)) {
    // JMW no in-built baro sources, so use this generic one
    if (info.flarm.IsDetected())
      /* FLARM emulates the Garmin $PGRMZ sentence, but emits the
         altitude above 1013.25 hPa - since the don't have a "FLARM"
         device driver, we use the auto-detected "isFlarm" flag
         here */
      info.ProvideWeakPressureAltitude(value);
    else
      info.ProvideBaroAltitudeTrue(value);
  }

  return true;
}
Пример #11
0
bool
DemoReplayGlue::Update(NMEAInfo &data, fixed time_scale)
{
  if (!UpdateTime())
    return true;

  fixed floor_alt = fixed_300;
  if (device_blackboard->Calculated().terrain_valid) {
    floor_alt += device_blackboard->Calculated().terrain_altitude;
  }

  bool retval;

  {
    ProtectedTaskManager::ExclusiveLease protected_task_manager(*task_manager);
    TaskAccessor ta(protected_task_manager, floor_alt);
    retval = DemoReplay::Update(time_scale, ta);
  }

  const AircraftState &s = aircraft.GetState();

  data.clock = s.time;
  data.alive.Update(data.clock);
  data.ProvideTime(s.time);
  data.location = s.location;
  data.location_available.Update(data.clock);
  data.ground_speed = s.ground_speed;
  data.ground_speed_available.Update(data.clock);
  data.track = s.track;
  data.track_available.Update(data.clock);
  data.gps_altitude = s.altitude;
  data.gps_altitude_available.Update(data.clock);
  data.ProvidePressureAltitude(s.altitude);
  data.ProvideBaroAltitudeTrue(s.altitude);
  data.gps.real = false;
  data.gps.replay = true;
  data.gps.simulator = false;

  return retval;
}
Пример #12
0
/*
!w,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>*hh<CR><LF>
<1>  Vector wind direction in degrees
<2>  Vector wind speed in 10ths of meters per second
<3>  Vector wind age in seconds
<4>  Component wind in 10ths of Meters per second + 500 (500 = 0, 495 = 0.5 m/s tailwind)
<5>  True altitude in Meters + 1000
<6>  Instrument QNH setting
<7>  True airspeed in 100ths of Meters per second
<8>  Variometer reading in 10ths of knots + 200
<9>  Averager reading in 10ths of knots + 200
<10> Relative variometer reading in 10ths of knots + 200
<11> Instrument MacCready setting in 10ths of knots
<12> Instrument Ballast setting in percent of capacity
<13> Instrument Bug setting
*hh  Checksum, XOR of all bytes
*/
static bool
cai_w(NMEAInputLine &line, NMEAInfo &info)
{
  SpeedVector wind;
  if (ReadSpeedVector(line, wind))
    info.ProvideExternalWind(wind.Reciprocal());

  line.skip(2);

  fixed value;
  if (line.read_checked(value))
    info.ProvideBaroAltitudeTrue(value - fixed(1000));

  if (line.read_checked(value))
    info.settings.ProvideQNH(value, info.clock);

  if (line.read_checked(value))
    info.ProvideTrueAirspeed(value / 100);

  if (line.read_checked(value))
    info.ProvideTotalEnergyVario(Units::ToSysUnit((value - fixed(200)) / 10,
                                                  unKnots));

  line.skip(2);

  int i;

  if (line.read_checked(i))
    info.settings.ProvideMacCready(Units::ToSysUnit(fixed(i) / 10, unKnots),
                                   info.clock);

  if (line.read_checked(i))
    info.settings.ProvideBallastFraction(fixed(i) / 100, info.clock);

  if (line.read_checked(i))
    info.settings.ProvideBugs(fixed(i) / 100, info.clock);

  return true;
}
Пример #13
0
/**
 * Parse a "$PILC,PDA1" sentence.
 *
 * Example: "$PILC,PDA1,1489,-3.21,274,15,58*7D"
 */
static bool
ParsePDA1(NMEAInputLine &line, NMEAInfo &info)
{
  fixed value;

  // altitude [m]
  int altitude;
  if (line.ReadChecked(altitude))
    info.ProvideBaroAltitudeTrue(fixed(altitude));

  // total energy vario [m/s]
  if (line.ReadChecked(value))
    info.ProvideTotalEnergyVario(value);

  // wind direction [degrees, kph]
  SpeedVector wind;
  if (ReadSpeedVector(line, wind))
    info.ProvideExternalWind(wind);

  // confidence [0..100]
  // not used

  return true;
}
Пример #14
0
int main(int argc, char **argv)
{
  plan_tests(47);

  const TCHAR *path = _T("output/test/test.igc");
  File::Delete(path);

  static const GeoPoint home(Angle::Degrees(fixed(7.7061111111111114)),
                             Angle::Degrees(fixed(51.051944444444445)));
  static const GeoPoint tp(Angle::Degrees(fixed(10.726111111111111)),
                           Angle::Degrees(fixed(50.6322)));

  static NMEAInfo i;
  i.clock = fixed_one;
  i.time = fixed(1);
  i.time_available.Update(i.clock);
  i.date_time_utc.year = 2010;
  i.date_time_utc.month = 9;
  i.date_time_utc.day = 4;
  i.date_time_utc.hour = 11;
  i.date_time_utc.minute = 22;
  i.date_time_utc.second = 33;
  i.location = home;
  i.location_available.Update(i.clock);
  i.gps_altitude = fixed(487);
  i.gps_altitude_available.Update(i.clock);
  i.ProvideBaroAltitudeTrue(fixed(490));

  IGCWriter writer(path, i);

  writer.WriteHeader(i.date_time_utc, _T("Pilot Name"), _T("ASK-21"),
                     _T("D-1234"), _T("34"), "FOO", _T("bar"));
  writer.StartDeclaration(i.date_time_utc, 3);
  writer.AddDeclaration(home, _T("Bergneustadt"));
  writer.AddDeclaration(tp, _T("Suhl"));
  writer.AddDeclaration(home, _T("Bergneustadt"));
  writer.EndDeclaration();

  i.date_time_utc.second += 5;
  writer.LogPoint(i);
  i.date_time_utc.second += 5;
  writer.LogEvent(i, "my_event");
  i.date_time_utc.second += 5;
  writer.LoggerNote(_T("my_note"));

  i.date_time_utc.second += 5;
  i.location = GeoPoint(Angle::Degrees(fixed(-7.7061111111111114)),
                        Angle::Degrees(fixed(-51.051944444444445)));
  writer.LogPoint(i);

  writer.Finish(i);
  writer.Sign();

  CheckTextFile(path, expect);

  GRecord grecord;
  grecord.Initialize();
  grecord.SetFileName(path);
  ok1(grecord.VerifyGRecordInFile());

  return exit_status();
}
Пример #15
0
bool
Replay::Update()
{
  if (replay == nullptr)
    return false;

  if (time_scale <= 0) {
    /* replay is paused */
    /* to avoid a big fast-forward with the next
       PeriodClock::ElapsedUpdate() call below after unpausing, update
       the clock each time we're called while paused */
    clock.Update();
    return true;
  }

  const double old_virtual_time = virtual_time;

  if (virtual_time >= 0) {
    /* update the virtual time */
    assert(clock.IsDefined());

    if (fast_forward < 0) {
      virtual_time += clock.ElapsedUpdate() * time_scale / 1000;
    } else {
      clock.Update();

      virtual_time += 1;
      if (virtual_time >= fast_forward)
        fast_forward = -1;
    }
  } else {
    /* if we ever received a valid time from the AbstractReplay, then
       virtual_time must be initialised */
    assert(!next_data.time_available);
  }

  if (cli == nullptr || fast_forward >= 0) {
    if (next_data.time_available && virtual_time < next_data.time)
      /* still not time to use next_data */
      return true;

    {
      std::lock_guard<Mutex> lock(device_blackboard->mutex);
      device_blackboard->SetReplayState() = next_data;
      device_blackboard->ScheduleMerge();
    }

    while (true) {
      if (!replay->Update(next_data)) {
        Stop();
        return false;
      }

      assert(!next_data.gps.real);

      if (next_data.time_available) {
        if (virtual_time < 0) {
          virtual_time = next_data.time;
          if (fast_forward >= 0)
            fast_forward += virtual_time;
          clock.Update();
          break;
        }

        if (next_data.time >= virtual_time)
          break;

        if (next_data.time < old_virtual_time) {
          /* time warp; that can happen on midnight wraparound during
             NMEA replay */
          virtual_time = next_data.time;
          break;
        }
      }
    }
  } else {
    while (cli->NeedData(virtual_time)) {
      if (!replay->Update(next_data)) {
        Stop();
        return false;
      }

      assert(!next_data.gps.real);

      if (next_data.time_available)
        cli->Update(next_data.time, next_data.location,
                    next_data.gps_altitude,
                    next_data.pressure_altitude);
    }

    if (virtual_time < 0) {
      virtual_time = cli->GetMaxTime();
      if (fast_forward >= 0)
        fast_forward += virtual_time;
      clock.Update();
    }

    const CatmullRomInterpolator::Record r = cli->Interpolate(virtual_time);
    const GeoVector v = cli->GetVector(virtual_time);

    NMEAInfo data = next_data;
    data.clock = virtual_time;
    data.alive.Update(data.clock);
    data.ProvideTime(virtual_time);
    data.location = r.location;
    data.location_available.Update(data.clock);
    data.ground_speed = v.distance;
    data.ground_speed_available.Update(data.clock);
    data.track = v.bearing;
    data.track_available.Update(data.clock);
    data.gps_altitude = r.gps_altitude;
    data.gps_altitude_available.Update(data.clock);
    data.ProvidePressureAltitude(r.baro_altitude);
    data.ProvideBaroAltitudeTrue(r.baro_altitude);

    {
      std::lock_guard<Mutex> lock(device_blackboard->mutex);
      device_blackboard->SetReplayState() = data;
      device_blackboard->ScheduleMerge();
    }
  }

  return true;
}
Пример #16
0
bool
IgcReplay::Update(NMEAInfo &basic)
{
  IGCFix fix;

  while (true) {
    if (!ReadPoint(fix, basic))
      return false;

    if (fix.time.IsPlausible())
      break;
  }

  basic.clock = fixed(fix.time.GetSecondOfDay());
  basic.alive.Update(basic.clock);
  basic.ProvideTime(basic.clock);
  basic.location = fix.location;
  basic.location_available.Update(basic.clock);

  if (fix.gps_altitude != 0) {
    basic.gps_altitude = fixed(fix.gps_altitude);
    basic.gps_altitude_available.Update(basic.clock);
  } else
    basic.gps_altitude_available.Clear();

  if (fix.pressure_altitude != 0) {
    basic.ProvidePressureAltitude(fixed(fix.pressure_altitude));
    basic.ProvideBaroAltitudeTrue(fixed(fix.pressure_altitude));
  } else {
    basic.pressure_altitude_available.Clear();
    basic.baro_altitude_available.Clear();
  }

  if (fix.enl >= 0) {
    basic.engine_noise_level = fix.enl;
    basic.engine_noise_level_available.Update(basic.clock);
  } else
    basic.engine_noise_level_available.Clear();

  if (fix.trt >= 0) {
    basic.track = Angle::Degrees(fixed(fix.trt));
    basic.track_available.Update(basic.clock);
  } else
    basic.track_available.Clear();

  if (fix.gsp >= 0) {
    basic.ground_speed = Units::ToSysUnit(fixed(fix.gsp),
                                          Unit::KILOMETER_PER_HOUR);
    basic.ground_speed_available.Update(basic.clock);
  } else
    basic.ground_speed_available.Clear();

  if (fix.ias >= 0) {
    fixed ias = Units::ToSysUnit(fixed(fix.ias), Unit::KILOMETER_PER_HOUR);
    if (fix.tas >= 0)
      basic.ProvideBothAirspeeds(ias,
                                 Units::ToSysUnit(fixed(fix.tas),
                                                  Unit::KILOMETER_PER_HOUR));
    else
      basic.ProvideIndicatedAirspeedWithAltitude(ias, basic.pressure_altitude);
  } else if (fix.tas >= 0)
    basic.ProvideTrueAirspeed(Units::ToSysUnit(fixed(fix.tas),
                                               Unit::KILOMETER_PER_HOUR));

  if (fix.siu >= 0) {
    basic.gps.satellites_used = fix.siu;
    basic.gps.satellites_used_available.Update(basic.clock);
  }

  basic.gps.real = false;
  basic.gps.replay = true;
  basic.gps.simulator = false;

  return true;
}