Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
// $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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
  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);
  }
Beispiel #7
0
/**
 * Parses a GSA sentence
 *
 * $--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
 * @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::GSA(NMEAInputLine &line, NMEAInfo &info)
{
  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);

  return true;
}
Beispiel #8
0
/**
 * 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 info NMEA_INFO struct to parse into
 * @return Parsing success
 * @see http://flarm.com/support/manual/FLARM_DataportManual_v5.00E.pdf
 */
bool
NMEAParser::PFLAU(NMEAInputLine &line, FLARM_STATE &flarm, fixed clock)
{
  flarm.available.Update(clock);

  // PFLAU,<RX>,<TX>,<GPS>,<Power>,<AlarmLevel>,<RelativeBearing>,<AlarmType>,
  //   <RelativeVertical>,<RelativeDistance>(,<ID>)
  flarm.rx = line.read(0);
  flarm.tx = line.read(false);
  flarm.gps = (FLARM_STATE::GPSStatus)line.read(FLARM_STATE::GPS_NONE);
  line.skip();
  flarm.alarm_level = (FLARM_TRAFFIC::AlarmType)
    line.read(FLARM_TRAFFIC::ALARM_NONE);

  return true;
}
Beispiel #9
0
/**
 * 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;
}
Beispiel #10
0
/**
 * 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;
}
Beispiel #11
0
/**
 * 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;
}
Beispiel #12
0
  void PDVSC(NMEAInputLine &line) {
    char command[4];
    line.read(command, ARRAY_SIZE(command));

    if (strcmp(command, "S") == 0)
      PDVSC_S(line);
    else if (strcmp(command, "R") == 0)
      PDVSC_R(line);
  }
Beispiel #13
0
bool
NMEAParser::PFLAU(NMEAInputLine &line, FlarmState &flarm, fixed time)
{
  flarm.available.Update(time);

  // PFLAU,<RX>,<TX>,<GPS>,<Power>,<AlarmLevel>,<RelativeBearing>,<AlarmType>,
  //   <RelativeVertical>,<RelativeDistance>(,<ID>)
  flarm.rx = line.read(0);
  flarm.tx = line.read(false);
  flarm.gps = (FlarmState::GPSStatus)
    line.read((int)FlarmState::GPSStatus::NONE);

  line.skip();
  flarm.alarm_level = (FlarmTraffic::AlarmType)
    line.read((int)FlarmTraffic::AlarmType::NONE);

  return true;
}
Beispiel #14
0
/**
 * Parses a GSA sentence
 *
 * $--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
 * @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::GSA(NMEAInputLine &line, NMEA_INFO *GPS_INFO)
{
  if (GPS_INFO->gps.Replay)
    return true;

  line.skip(2);

  // satellites are in items 4-15 of GSA string (4-15 is 1-indexed)
  for (unsigned i = 0; i < MAXSATELLITES; i++)
    GPS_INFO->gps.SatelliteIDs[i] = line.read(0);

  GSAAvailable = true;
  return true;
}
Beispiel #15
0
  void PDVSC_R(NMEAInputLine &line) {
    char name[64];
    line.read(name, ARRAY_SIZE(name));

    auto i = settings.find(name);
    if (i == settings.end())
      return;

    const char *value = i->second.c_str();

    ConsoleOperationEnvironment env;

    char buffer[512];
    snprintf(buffer, ARRAY_SIZE(buffer), "PDVSC,A,%s,%s", name, value);
    PortWriteNMEA(*port, buffer, env);
  }
Beispiel #16
0
bool
NMEAParser::GLL(NMEAInputLine &line, NMEAInfo &info)
{
  /*
   * $--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
   */

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  fixed this_time = TimeModify(line.read(fixed_zero), info.date_time_utc,
                               info.date_available);
  this_time = TimeAdvanceTolerance(this_time);

  bool gps_valid = !NAVWarn(line.read_first_char());

  if (!TimeHasAdvanced(this_time, info))
    return true;

  if (!gps_valid)
    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;
}
Beispiel #17
0
static bool
LXWP0(NMEAInputLine &line, NMEA_INFO *GPS_INFO, bool enable_baro)
{
  /*
  $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;
  GPS_INFO->AirspeedAvailable = line.read_checked(airspeed);

  fixed alt = line.read(fixed_zero);

  if (GPS_INFO->AirspeedAvailable) {
    GPS_INFO->TrueAirspeed = Units::ToSysUnit(airspeed, unKiloMeterPerHour);
    GPS_INFO->IndicatedAirspeed =
      GPS_INFO->TrueAirspeed / AtmosphericPressure::AirDensityRatio(alt);
  }

  if (enable_baro) {
    GPS_INFO->BaroAltitudeAvailable = true;
    GPS_INFO->BaroAltitude = alt; // ToDo check if QNH correction is needed!
  }

  GPS_INFO->TotalEnergyVarioAvailable =
    line.read_checked(GPS_INFO->TotalEnergyVario);

  line.skip(6);

  GPS_INFO->ExternalWindAvailable = ReadSpeedVector(line, GPS_INFO->wind);

  TriggerVarioUpdate();

  return true;
}
Beispiel #18
0
static bool
PZAN5(NMEAInputLine &line, NMEAInfo &info)
{
  // $PZAN5,VA,MUEHL,123.4,KM,T,234*cc

  char state[3];
  line.read(state, 3);

  if (strcmp(state, "SF") == 0) {
    info.switch_state.flight_mode = SwitchInfo::FlightMode::CRUISE;
    info.switch_state.speed_command = true;
  } else if (strcmp(state, "VA") == 0) {
    info.switch_state.flight_mode = SwitchInfo::FlightMode::CIRCLING;
    info.switch_state.speed_command = false;
  } else
    return false;

  info.switch_state_available = true;
  return true;
}
Beispiel #19
0
static bool
PDVDV(NMEAInputLine &line, NMEAInfo &info)
{
  fixed value;

  if (line.read_checked(value))
    info.ProvideTotalEnergyVario(value / 10);

  bool ias_available = line.read_checked(value);
  fixed tas_ratio = line.read(fixed(1024)) / 1024;
  if (ias_available)
    info.ProvideBothAirspeeds(value / 10, value / 10 * tas_ratio);

  //hasVega = true;

  if (line.read_checked(value))
    info.ProvidePressureAltitude(value);

  return true;
}
Beispiel #20
0
static bool
PZAN5(NMEAInputLine &line, NMEA_INFO *GPS_INFO)
{
  // $PZAN5,VA,MUEHL,123.4,KM,T,234*cc

  char state[3];
  line.read(state, 3);

  if (strcmp(state, "SF") == 0) {
    GPS_INFO->SwitchState.FlightMode = SWITCH_INFO::MODE_CRUISE;
    GPS_INFO->SwitchState.SpeedCommand = true;
  } else if (strcmp(state, "VA") == 0) {
    GPS_INFO->SwitchState.FlightMode = SWITCH_INFO::MODE_CIRCLING;
    GPS_INFO->SwitchState.SpeedCommand = false;
  } else
    return false;

  GPS_INFO->SwitchStateAvailable = true;
  return true;
}
Beispiel #21
0
// RMN: Volkslogger
// Source data:
// $PGCS,1,0EC0,FFF9,0C6E,02*61
// $PGCS,1,0EC0,FFFA,0C6E,03*18
static bool
vl_PGCS1(NMEAInputLine &line, NMEA_INFO *GPS_INFO, bool enable_baro)
{
  GPS_STATE &gps = GPS_INFO->gps;

  if (line.read(1) != 1)
    return false;

  /* pressure sensor */
  line.skip();

  // four characers, hex, barometric altitude
  long altitude = line.read_hex(0L);

  if (enable_baro) {
    if (altitude > 60000)
      /* Assuming that altitude has wrapped around.  60 000 m occurs
         at QNH ~2000 hPa */
      altitude -= 65535;

    GPS_INFO->BaroAltitude =
      GPS_INFO->pressure.AltitudeToQNHAltitude(fixed(altitude));

    GPS_INFO->BaroAltitudeAvailable = true;
  }

  // ExtractParameter(String,ctemp,3);
  // four characters, hex, constant.  Value 1371 (dec)

  // nSatellites = (int)(min(12,HexStrToDouble(ctemp, NULL)));

  if (gps.SatellitesUsed <= 0) {
    gps.SatellitesUsed = 4;
    // just to make XCSoar quit complaining.  VL doesn't tell how many
    // satellites it uses.  Without this XCSoar won't do wind
    // measurements.
  }

  return false;
}
Beispiel #22
0
/**
 * Parses an angle in the form "DDDMM.SSS".  Minutes are 0..59, and
 * seconds are 0..999.
 */
static bool
ReadPositiveAngle(NMEAInputLine &line, Angle &a)
{
  char buffer[32], *endptr;
  line.read(buffer, sizeof(buffer));

  char *dot = strchr(buffer, '.');
  if (dot < buffer + 3)
    return false;

  double x = strtod(dot - 2, &endptr);
  if (x < 0 || x >= 60 || *endptr != 0)
    return false;

  dot[-2] = 0;
  long y = strtol(buffer, &endptr, 10);
  if (y < 0 || endptr == buffer || *endptr != 0)
    return false;

  a = Angle::degrees(fixed(y) + fixed(x) / 60);
  return true;
}
Beispiel #23
0
static bool
ReadDate(NMEAInputLine &line, BrokenDate &date)
{
  char buffer[9];
  line.read(buffer, 9);

  if (strlen(buffer) != 6)
    return false;

  BrokenDate new_value;
  new_value.year = atoi(buffer + 4) + 2000;
  buffer[4] = '\0';
  new_value.month = atoi(buffer + 2);
  buffer[2] = '\0';
  new_value.day = atoi(buffer);

  if (!new_value.Plausible())
    return false;

  date = new_value;
  return true;
}
Beispiel #24
0
/**
 * Parses a PFLAA sentence
 * (Data on other moving objects around)
 * @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::PFLAA(NMEAInputLine &line, NMEA_INFO *GPS_INFO)
{
  FLARM_STATE &flarm = GPS_INFO->flarm;

  isFlarm = true;

  // calculate relative east and north projection to lat/lon

  Angle delta_lat = Angle::degrees(fixed(0.01));
  Angle delta_lon = Angle::degrees(fixed(0.01));

  GeoPoint plat = GPS_INFO->Location;
  plat.Latitude += delta_lat;
  GeoPoint plon = GPS_INFO->Location;
  plon.Longitude += delta_lon;

  fixed dlat = Distance(GPS_INFO->Location, plat);
  fixed dlon = Distance(GPS_INFO->Location, plon);

  fixed FLARM_NorthingToLatitude(0);
  fixed FLARM_EastingToLongitude(0);

  if (positive(fabs(dlat)) && positive(fabs(dlon))) {
    FLARM_NorthingToLatitude = delta_lat.value_degrees() / dlat;
    FLARM_EastingToLongitude = delta_lon.value_degrees() / dlon;
  }

  // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>,
  //   <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType>
  FLARM_TRAFFIC traffic;
  traffic.AlarmLevel = line.read(0);
  traffic.RelativeNorth = line.read(fixed_zero);
  traffic.RelativeEast = line.read(fixed_zero);
  traffic.RelativeAltitude = line.read(fixed_zero);
  traffic.IDType = line.read(0);

  // 5 id, 6 digit hex
  char id_string[16];
  line.read(id_string, 16);
  traffic.ID.parse(id_string, NULL);

  traffic.TrackBearing = Angle::degrees(line.read(fixed_zero));
  traffic.TurnRate = line.read(fixed_zero);
  traffic.Speed = line.read(fixed_zero);
  traffic.ClimbRate = line.read(fixed_zero);
  traffic.Type = (FLARM_TRAFFIC::AircraftType)line.read(0);

  FLARM_TRAFFIC *flarm_slot = flarm.FindTraffic(traffic.ID);
  if (flarm_slot == NULL) {
    flarm_slot = flarm.AllocateTraffic();
    if (flarm_slot == NULL)
      // no more slots available
      return false;

    flarm_slot->ID = traffic.ID;

    flarm.NewTraffic = true;
    InputEvents::processGlideComputer(GCE_FLARM_NEWTRAFFIC);
  }

  // set time of fix to current time
  flarm_slot->Time_Fix = GPS_INFO->Time;

  // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>,
  //   <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType>
  flarm_slot->AlarmLevel = traffic.AlarmLevel;
  flarm_slot->RelativeNorth = traffic.RelativeNorth;
  flarm_slot->RelativeEast = traffic.RelativeEast;
  flarm_slot->RelativeAltitude = traffic.RelativeAltitude;
  flarm_slot->IDType = traffic.IDType;
  flarm_slot->TrackBearing = traffic.TrackBearing;
  flarm_slot->TurnRate = traffic.TurnRate;
  flarm_slot->Speed = traffic.Speed;
  flarm_slot->ClimbRate = traffic.ClimbRate;
  flarm_slot->Type = traffic.Type;

  // 1 relativenorth, meters
  flarm_slot->Location.Latitude = Angle::degrees(flarm_slot->RelativeNorth
                                        * FLARM_NorthingToLatitude) + GPS_INFO->Location.Latitude;

  // 2 relativeeast, meters
  flarm_slot->Location.Longitude = Angle::degrees(flarm_slot->RelativeEast
                                         * FLARM_EastingToLongitude) + GPS_INFO->Location.Longitude;

  // alt
  flarm_slot->Altitude = flarm_slot->RelativeAltitude + GPS_INFO->GPSAltitude;

  flarm_slot->Average30s = flarmCalculations.Average30s(flarm_slot->ID,
                                                        GPS_INFO->Time,
                                                        flarm_slot->Altitude);

  // QUESTION TB: never returns true?!
  return false;
}
Beispiel #25
0
bool
NMEAParser::RMC(NMEAInputLine &line, NMEAInfo &info)
{
  /*
   * $--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
   */

  fixed this_time = line.read(fixed_zero);

  bool gps_valid = !NAVWarn(line.read_first_char());

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  fixed speed;
  bool ground_speed_available = 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;

  this_time = TimeModify(this_time, info.date_time_utc, info.date_available);
  this_time = TimeAdvanceTolerance(this_time);

  if (!TimeHasAdvanced(this_time, info))
    return true;

  if (!gps_valid)
    info.location_available.Clear();
  else if (valid_location)
    info.location_available.Update(info.clock);

  if (valid_location)
    info.location = location;

  if (ground_speed_available) {
    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).AsBearing();
    info.track_available.Update(info.clock);
  }

  info.gps.real = real;
#ifdef ANDROID
  info.gps.android_internal_gps = false;
#endif

  return true;
}
Beispiel #26
0
/**
 * Parses a GGA sentence
 *
 * $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
 *
 * Field Number:
 *  1) Universal Time Coordinated (UTC)
 *  2) Latitude
 *  3) N or S (North or South)
 *  4) Longitude
 *  5) E or W (East or West)
 *  6) GPS Quality Indicator,
 *     0 - fix not available,
 *     1 - GPS fix,
 *     2 - Differential GPS fix
 *     (values above 2 are 2.3 features)
 *     3 = PPS fix
 *     4 = Real Time Kinematic
 *     5 = Float RTK
 *     6 = estimated (dead reckoning)
 *     7 = Manual input mode
 *     8 = Simulation mode
 *  7) Number of satellites in view, 00 - 12
 *  8) Horizontal Dilution of precision (meters)
 *  9) Antenna Altitude above/below mean-sea-level (geoid) (in meters)
 * 10) Units of antenna altitude, meters
 * 11) Geoidal separation, the difference between the WGS-84 earth
 *     ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level
 *     below ellipsoid
 * 12) Units of geoidal separation, meters
 * 13) Age of differential GPS data, time in seconds since last SC104
 *     type 1 or 9 update, null field when DGPS is not used
 * 14) Differential reference station ID, 0000-1023
 * 15) 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::GGA(NMEAInputLine &line, NMEA_INFO *GPS_INFO)
{
  GPS_STATE &gps = GPS_INFO->gps;

  if (gps.Replay)
    return true;

  GGAAvailable = true;

  fixed ThisTime = TimeModify(line.read(fixed_zero), GPS_INFO->DateTime);

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  gps.FixQuality = line.read(0);
  if (gps.FixQuality != 1 && gps.FixQuality != 2)
    gpsValid = false;

  int nSatellites = min(16, line.read(0));
  if (nSatellites == 0)
    gpsValid = false;

  if (!activeGPS)
    return true;

  gps.SatellitesUsed = nSatellites;

  if (!TimeHasAdvanced(ThisTime, GPS_INFO))
    return false;

  if (valid_location)
    GPS_INFO->Location = location;
  else
    GPS_INFO->gps.NAVWarning = true;

  gps.HDOP = line.read(fixed_zero);

  if (RMZAvailable) {
    GPS_INFO->BaroAltitudeAvailable = true;
    GPS_INFO->BaroAltitude = RMZAltitude;
  } else if (RMAAvailable) {
    GPS_INFO->BaroAltitudeAvailable = true;
    GPS_INFO->BaroAltitude = RMAAltitude;
  }

  // VENTA3 CONDOR ALTITUDE
  // "Altitude" should always be GPS Altitude.

  bool altitude_available = ReadAltitude(line, GPS_INFO->GPSAltitude);
  if (!altitude_available)
    GPS_INFO->GPSAltitude = fixed_zero;

  fixed GeoidSeparation;
  if (ReadAltitude(line, GeoidSeparation)) {
    // No real need to parse this value,
    // but we do assume that no correction is required in this case

    if (!altitude_available)
      /* Some devices, such as the "LG Incite Cellphone" seem to be
         severely bugged, and report the GPS altitude in the Geoid
         column.  That sucks! */
      GPS_INFO->GPSAltitude = GeoidSeparation;
  } else {
    // need to estimate Geoid Separation internally (optional)
    // FLARM uses MSL altitude
    //
    // Some others don't.
    //
    // If the separation doesn't appear in the sentence,
    // we can assume the GPS unit is giving ellipsoid height
    //
    if (!HaveCondorDevice()) {
      // JMW TODO really need to know the actual device..
      GeoidSeparation = LookupGeoidSeparation(GPS_INFO->Location);
      GPS_INFO->GPSAltitude -= GeoidSeparation;
    }
  }

  return true;
}
Beispiel #27
0
/**
 * 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 GPS_INFO GPS_INFO struct to parse into
 * @return Parsing success
 */
bool
NMEAParser::RMC(NMEAInputLine &line, NMEA_INFO *GPS_INFO)
{
  fixed ThisTime = TimeModify(line.read(fixed_zero), GPS_INFO->DateTime);

  gpsValid = !NAVWarn(line.read_first_char());

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  GPS_STATE &gps = GPS_INFO->gps;

  gps.Connected = 2;

  if (!activeGPS)
    return true;

  fixed speed = line.read(fixed_zero);
  gps.MovementDetected = speed > fixed_two;

  if (gps.Replay)
    // block actual GPS signal if not moving and a log is being replayed
    return true;

  gps.NAVWarning = !gpsValid;

  fixed TrackBearing = line.read(fixed_zero);

  // JMW get date info first so TimeModify is accurate
  char date_buffer[9];
  line.read(date_buffer, 9);

  GPS_INFO->DateTime.year = atoi(&date_buffer[4]) + 2000;
  date_buffer[4] = '\0';
  GPS_INFO->DateTime.month = atoi(&date_buffer[2]);
  date_buffer[2] = '\0';
  GPS_INFO->DateTime.day = atoi(&date_buffer[0]);

  if (!TimeHasAdvanced(ThisTime, GPS_INFO))
    return false;

  if (valid_location)
    GPS_INFO->Location = location;
  else
    GPS_INFO->gps.NAVWarning = true;

  GPS_INFO->GroundSpeed = Units::ToSysUnit(speed, unKnots);

  if (GPS_INFO->GroundSpeed > fixed_one) {
    // JMW don't update bearing unless we're moving
    GPS_INFO->TrackBearing = Angle::degrees(TrackBearing).as_bearing();
  }

  if (!gps.Replay) {
    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 don't emit GGA sentence
    if (!gpsValid)
      gps.SatellitesUsed = 0;
    else
      gps.SatellitesUsed = -1;
  }

  // say we are updated every time we get this,
  // so infoboxes get refreshed if GPS connected
  TriggerGPSUpdate();

  return true;
}
Beispiel #28
0
bool
NMEAParser::GGA(NMEAInputLine &line, NMEAInfo &info)
{
  /*
   * $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
   *
   * Field Number:
   *  1) Universal Time Coordinated (UTC)
   *  2) Latitude
   *  3) N or S (North or South)
   *  4) Longitude
   *  5) E or W (East or West)
   *  6) GPS Quality Indicator,
   *     0 - fix not available,
   *     1 - GPS fix,
   *     2 - Differential GPS fix
   *     (values above 2 are 2.3 features)
   *     3 = PPS fix
   *     4 = Real Time Kinematic
   *     5 = Float RTK
   *     6 = estimated (dead reckoning)
   *     7 = Manual input mode
   *     8 = Simulation mode
   *  7) Number of satellites in view, 00 - 12
   *  8) Horizontal Dilution of precision (meters)
   *  9) Antenna Altitude above/below mean-sea-level (geoid) (in meters)
   * 10) Units of antenna altitude, meters
   * 11) Geoidal separation, the difference between the WGS-84 earth
   *     ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level
   *     below ellipsoid
   * 12) Units of geoidal separation, meters
   * 13) Age of differential GPS data, time in seconds since last SC104
   *     type 1 or 9 update, null field when DGPS is not used
   * 14) Differential reference station ID, 0000-1023
   * 15) Checksum
   */
  GPSState &gps = info.gps;

  fixed this_time = TimeModify(line.read(fixed_zero), info.date_time_utc,
                               info.date_available);
  this_time = TimeAdvanceTolerance(this_time);

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  gps.fix_quality = line.read(0);
  gps.satellites_used_available.Update(info.clock);
  gps.satellites_used = min(16, line.read(-1));

  if (!TimeHasAdvanced(this_time, info))
    return true;

  (void)valid_location;
  /* JMW: note ignore location updates from GGA -- definitive frame is GPRMC sentence
  if (!gpsValid)
    info.LocationAvailable.Clear();
  else if (valid_location)
    info.LocationAvailable.Update(info.clock);

  if (valid_location)
    info.Location = location;
  */

  info.gps.real = real;
#ifdef ANDROID
  info.gps.android_internal_gps = false;
#endif

  gps.hdop = line.read(fixed_zero);

  // VENTA3 CONDOR ALTITUDE
  // "Altitude" should always be GPS Altitude.

  bool altitude_available = ReadAltitude(line, info.gps_altitude);
  if (altitude_available)
    info.gps_altitude_available.Update(info.clock);
  else
    info.gps_altitude_available.Clear();

  fixed geoid_separation;
  if (ReadAltitude(line, geoid_separation)) {
    // No real need to parse this value,
    // but we do assume that no correction is required in this case

    if (!altitude_available) {
      /* Some devices, such as the "LG Incite Cellphone" seem to be
         severely bugged, and report the GPS altitude in the Geoid
         column.  That sucks! */
      info.gps_altitude = geoid_separation;
      info.gps_altitude_available.Update(info.clock);
    }
  } else {
    // need to estimate Geoid Separation internally (optional)
    // FLARM uses MSL altitude
    //
    // Some others don't.
    //
    // If the separation doesn't appear in the sentence,
    // we can assume the GPS unit is giving ellipsoid height
    //
    if (use_geoid) {
      // JMW TODO really need to know the actual device..
      geoid_separation = EGM96::LookupSeparation(info.location);
      info.gps_altitude -= geoid_separation;
    }
  }

  return true;
}
Beispiel #29
0
/**
 * Parses a PFLAA sentence
 * (Data on other moving objects around)
 * @param String Input string
 * @param params Parameter array
 * @param nparams Number of parameters
 * @param info NMEA_INFO struct to parse into
 * @return Parsing success
 * @see http://flarm.com/support/manual/FLARM_DataportManual_v5.00E.pdf
 */
bool
NMEAParser::PFLAA(NMEAInputLine &line, NMEAInfo &info)
{
  FLARM_STATE &flarm = info.flarm;

  // PFLAA,<AlarmLevel>,<RelativeNorth>,<RelativeEast>,<RelativeVertical>,
  //   <IDType>,<ID>,<Track>,<TurnRate>,<GroundSpeed>,<ClimbRate>,<AcftType>
  FLARM_TRAFFIC traffic;
  traffic.alarm_level = (FLARM_TRAFFIC::AlarmType)
    line.read(FLARM_TRAFFIC::ALARM_NONE);

  fixed value;
  bool stealth = false;

  if (!line.read_checked(value))
    // Relative North is required !
    return true;
  traffic.relative_north = value;

  if (!line.read_checked(value))
    // Relative East is required !
    return true;
  traffic.relative_east = value;

  if (!line.read_checked(value))
    // Relative Altitude is required !
    return true;
  traffic.relative_altitude = value;

  line.skip(); /* id type */

  // 5 id, 6 digit hex
  char id_string[16];
  line.read(id_string, 16);
  traffic.id.parse(id_string, NULL);

  traffic.track_received = line.read_checked(value);
  if (!traffic.track_received) {
    // Field is empty in stealth mode
    stealth = true;
    traffic.track = Angle::zero();
  } else
    traffic.track = Angle::degrees(value);

  traffic.turn_rate_received = line.read_checked(value);
  if (!traffic.turn_rate_received) {
    // Field is empty in stealth mode
    traffic.turn_rate = fixed_zero;
  } else
    traffic.turn_rate = value;

  traffic.speed_received = line.read_checked(value);
  if (!traffic.speed_received) {
    // Field is empty in stealth mode
    stealth = true;
    traffic.speed = fixed_zero;
  } else
    traffic.speed = value;

  traffic.climb_rate_received = line.read_checked(value);
  if (!traffic.climb_rate_received) {
    // Field is empty in stealth mode
    stealth = true;
    traffic.climb_rate = fixed_zero;
  } else
    traffic.climb_rate = value;

  traffic.stealth = stealth;

  traffic.type = (FLARM_TRAFFIC::AircraftType)line.read(0);

  FLARM_TRAFFIC *flarm_slot = flarm.FindTraffic(traffic.id);
  if (flarm_slot == NULL) {
    flarm_slot = flarm.AllocateTraffic();
    if (flarm_slot == NULL)
      // no more slots available
      return true;

    flarm_slot->Clear();
    flarm_slot->id = traffic.id;

    flarm.NewTraffic = true;
  }

  // set time of fix to current time
  flarm_slot->valid.Update(info.clock);

  flarm_slot->Update(traffic);

  return true;
}
Beispiel #30
0
/**
 * Parses a GGA sentence
 *
 * $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
 *
 * Field Number:
 *  1) Universal Time Coordinated (UTC)
 *  2) Latitude
 *  3) N or S (North or South)
 *  4) Longitude
 *  5) E or W (East or West)
 *  6) GPS Quality Indicator,
 *     0 - fix not available,
 *     1 - GPS fix,
 *     2 - Differential GPS fix
 *     (values above 2 are 2.3 features)
 *     3 = PPS fix
 *     4 = Real Time Kinematic
 *     5 = Float RTK
 *     6 = estimated (dead reckoning)
 *     7 = Manual input mode
 *     8 = Simulation mode
 *  7) Number of satellites in view, 00 - 12
 *  8) Horizontal Dilution of precision (meters)
 *  9) Antenna Altitude above/below mean-sea-level (geoid) (in meters)
 * 10) Units of antenna altitude, meters
 * 11) Geoidal separation, the difference between the WGS-84 earth
 *     ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level
 *     below ellipsoid
 * 12) Units of geoidal separation, meters
 * 13) Age of differential GPS data, time in seconds since last SC104
 *     type 1 or 9 update, null field when DGPS is not used
 * 14) Differential reference station ID, 0000-1023
 * 15) 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::GGA(NMEAInputLine &line, NMEAInfo &info)
{
  GPSState &gps = info.gps;

  GGAAvailable = true;

  fixed ThisTime = TimeModify(line.read(fixed_zero), info.date_time_utc,
                              info.date_available);
  ThisTime = TimeAdvanceTolerance(ThisTime);

  GeoPoint location;
  bool valid_location = ReadGeoPoint(line, location);

  gps.fix_quality = line.read(0);
  gps.satellites_used = min(16, line.read(-1));

  if (!TimeHasAdvanced(ThisTime, info))
    return true;

  (void)valid_location;
  /* JMW: note ignore location updates from GGA -- definitive frame is GPRMC sentence
  if (!gpsValid)
    info.LocationAvailable.Clear();
  else if (valid_location)
    info.LocationAvailable.Update(info.clock);

  if (valid_location)
    info.Location = location;
  */

  info.gps.real = real;
#ifdef ANDROID
  info.gps.android_internal_gps = false;
#endif

  gps.hdop = line.read(fixed_zero);

  // VENTA3 CONDOR ALTITUDE
  // "Altitude" should always be GPS Altitude.

  bool altitude_available = ReadAltitude(line, info.gps_altitude);
  if (altitude_available)
    info.gps_altitude_available.Update(info.clock);
  else {
    info.gps_altitude = fixed_zero;
    info.gps_altitude_available.Clear();
  }

  fixed GeoidSeparation;
  if (ReadAltitude(line, GeoidSeparation)) {
    // No real need to parse this value,
    // but we do assume that no correction is required in this case

    if (!altitude_available) {
      /* Some devices, such as the "LG Incite Cellphone" seem to be
         severely bugged, and report the GPS altitude in the Geoid
         column.  That sucks! */
      info.gps_altitude = GeoidSeparation;
      info.gps_altitude_available.Update(info.clock);
    }
  } else {
    // need to estimate Geoid Separation internally (optional)
    // FLARM uses MSL altitude
    //
    // Some others don't.
    //
    // If the separation doesn't appear in the sentence,
    // we can assume the GPS unit is giving ellipsoid height
    //
    if (use_geoid) {
      // JMW TODO really need to know the actual device..
      GeoidSeparation = LookupGeoidSeparation(info.location);
      info.gps_altitude -= GeoidSeparation;
    }
  }

  return true;
}