void DeviceBlackboard::Merge() { real_data.Reset(); for (unsigned i = 0; i < NUMDEV; ++i) { if (!per_device_data[i].connected) continue; per_device_data[i].UpdateClock(); per_device_data[i].Expire(); real_data.Complement(per_device_data[i]); } if (replay_data.connected) { /* the replay may run at a higher speed; use NMEA_INFO::Time as a "fake wallclock" to prevent them from expiring too quickly */ replay_data.clock = replay_data.time; replay_data.Expire(); SetBasic() = replay_data; } else if (simulator_data.connected) { simulator_data.UpdateClock(); simulator_data.Expire(); SetBasic() = simulator_data; } else { SetBasic() = real_data; } }
void DeviceBlackboard::tick() { SetBasic().expire(); // calculate fast data to complete aircraft state computer.Compute(SetBasic(), LastBasic(), Calculated(), SettingsComputer()); if (Basic().Time!= LastBasic().Time) { state_last = Basic(); } }
void DeviceBlackboard::Merge() { NMEAInfo &basic = SetBasic(); real_data.Reset(); for (unsigned i = 0; i < unsigned(NUMDEV); ++i) { if (!per_device_data[i].alive) continue; per_device_data[i].UpdateClock(); per_device_data[i].Expire(); real_data.Complement(per_device_data[i]); } real_clock.Normalise(real_data); if (replay_data.alive) { replay_data.Expire(); basic = replay_data; /* WrapClock operates on the replay_data copy to avoid feeding back BrokenDate modifications to the NMEA parser, as this would trigger its time warp checks */ replay_clock.Normalise(basic); } else if (simulator_data.alive) { simulator_data.UpdateClock(); simulator_data.Expire(); basic = simulator_data; } else { basic = real_data; } }
void DeviceBlackboard::Merge() { real_data.reset(); for (unsigned i = 0; i < NUMDEV; ++i) { per_device_data[i].expire(); real_data.complement(per_device_data[i]); } if (replay_data.Connected) { replay_data.expire(); SetBasic() = replay_data; } else if (simulator_data.Connected) { simulator_data.expire(); SetBasic() = simulator_data; } else { SetBasic() = real_data; } computer.Fill(SetBasic(), SettingsComputer()); ProcessFLARM(); if (last_location_available != Basic().LocationAvailable) { last_location_available = Basic().LocationAvailable; TriggerGPSUpdate(); } else if (last_vario_counter != Basic().VarioCounter) { last_vario_counter = Basic().VarioCounter; TriggerGPSUpdate(); } if (last_te_vario_available != Basic().TotalEnergyVarioAvailable || last_netto_vario_available != Basic().NettoVarioAvailable) { last_te_vario_available = Basic().TotalEnergyVarioAvailable; last_netto_vario_available = Basic().NettoVarioAvailable; TriggerVarioUpdate(); } }
/** * Calculates location, altitude, average climb speed and * looks up the callsign of each target */ void DeviceBlackboard::ProcessFLARM() { const NMEA_INFO &basic = Basic(); FLARM_STATE &flarm = SetBasic().flarm; const FLARM_STATE &last_flarm = LastBasic().flarm; // if (FLARM data is available) if (!flarm.available || flarm.traffic.empty()) return; fixed FLARM_NorthingToLatitude(0); fixed FLARM_EastingToLongitude(0); if (basic.LocationAvailable) { // Precalculate relative east and north projection to lat/lon // for Location calculations of each target Angle delta_lat = Angle::degrees(fixed(0.01)); Angle delta_lon = Angle::degrees(fixed(0.01)); GeoPoint plat = basic.Location; plat.Latitude += delta_lat; GeoPoint plon = basic.Location; plon.Longitude += delta_lon; fixed dlat = Distance(basic.Location, plat); fixed dlon = Distance(basic.Location, plon); if (positive(fabs(dlat)) && positive(fabs(dlon))) { FLARM_NorthingToLatitude = delta_lat.value_degrees() / dlat; FLARM_EastingToLongitude = delta_lon.value_degrees() / dlon; } } // for each item in traffic for (unsigned i = 0; i < flarm.traffic.size(); i++) { FLARM_TRAFFIC &traffic = flarm.traffic[i]; // if we don't know the target's name yet if (!traffic.HasName()) { // lookup the name of this target's id const TCHAR *fname = FlarmDetails::LookupCallsign(traffic.id); if (fname != NULL) traffic.name = fname; } // Calculate distance traffic.distance = hypot(traffic.relative_north, traffic.relative_east); // Calculate Location traffic.location_available = basic.LocationAvailable; if (traffic.location_available) { traffic.location.Latitude = Angle::degrees(traffic.relative_north * FLARM_NorthingToLatitude) + basic.Location.Latitude; traffic.location.Longitude = Angle::degrees(traffic.relative_east * FLARM_EastingToLongitude) + basic.Location.Longitude; } // Calculate absolute altitude traffic.altitude_available = basic.GPSAltitudeAvailable; if (traffic.altitude_available) traffic.altitude = traffic.relative_altitude + basic.GPSAltitude; // Calculate average climb rate traffic.climb_rate_avg30s_available = traffic.altitude_available; if (traffic.climb_rate_avg30s_available) traffic.climb_rate_avg30s = flarmCalculations.Average30s(traffic.id, basic.Time, traffic.altitude); // The following calculations are only relevant for targets // where information is missing if (traffic.track_received || traffic.turn_rate_received || traffic.speed_received || traffic.climb_rate_received) continue; // Check if the target has been seen before in the last seconds const FLARM_TRAFFIC *last_traffic = last_flarm.FindTraffic(traffic.id); if (last_traffic == NULL || !last_traffic->valid) continue; // Calculate the time difference between now and the last contact fixed dt = traffic.valid.GetTimeDifference(last_traffic->valid); if (positive(dt)) { // Calculate the immediate climb rate if (!traffic.climb_rate_received) traffic.climb_rate = (traffic.relative_altitude - last_traffic->relative_altitude) / dt; } else { // Since the time difference is zero (or negative) // we can just copy the old values if (!traffic.climb_rate_received) traffic.climb_rate = last_traffic->climb_rate; } if (positive(dt) && traffic.location_available && last_traffic->location_available) { // Calculate the GeoVector between now and the last contact GeoVector vec = last_traffic->location.distance_bearing(traffic.location); if (!traffic.track_received) traffic.track = vec.Bearing; // Calculate the turn rate if (!traffic.turn_rate_received) traffic.turn_rate = (traffic.track - last_traffic->track).as_delta().value_degrees() / dt; // Calculate the speed [m/s] if (!traffic.speed_received) traffic.speed = vec.Distance / dt; } else { // Since the time difference is zero (or negative) // we can just copy the old values if (!traffic.track_received) traffic.track = last_traffic->track; if (!traffic.turn_rate_received) traffic.turn_rate = last_traffic->turn_rate; if (!traffic.speed_received) traffic.speed = last_traffic->speed; } } }
void SetBaroAlt(double x) { SetBasic().BaroAltitude = x; }
void SetBaroAlt(fixed x) { SetBasic().BaroAltitude = x; }