void DeviceDescriptor::Close() { assert(InMainThread()); assert(!IsBorrowed()); CancelAsync(); #ifdef HAVE_INTERNAL_GPS delete internal_sensors; internal_sensors = nullptr; #endif #ifdef ANDROID delete droidsoar_v2; droidsoar_v2 = nullptr; for (unsigned i=0; i<sizeof i2cbaro/sizeof i2cbaro[0]; i++) { delete i2cbaro[i]; i2cbaro[i] = nullptr; } delete nunchuck; nunchuck = nullptr; delete voltage; voltage = nullptr; #endif /* safely delete the Device object */ Device *old_device = device; { const ScopeLock protect(mutex); device = nullptr; /* after leaving this scope, no other thread may use the old object; to avoid locking the mutex for too long, the "delete" is called after the scope */ } delete old_device; delete second_device; second_device = nullptr; Port *old_port = port; port = nullptr; delete old_port; ticker = false; { const ScopeLock lock(device_blackboard->mutex); device_blackboard->SetRealState(index).Reset(); device_blackboard->ScheduleMerge(); } settings_sent.Clear(); settings_received.Clear(); }
bool DeviceDescriptor::PutQNH(const AtmosphericPressure &value, OperationEnvironment &env) { assert(InMainThread()); if (device == nullptr || settings_sent.CompareQNH(value) || !config.sync_to_device) return true; if (!Borrow()) /* TODO: postpone until the borrowed device has been returned */ return false; ScopeReturnDevice restore(*this, env); if (!device->PutQNH(value, env)) return false; ScopeLock protect(device_blackboard->mutex); NMEAInfo &basic = device_blackboard->SetRealState(index); settings_sent.qnh = value; settings_sent.qnh_available.Update(basic.clock); return true; }
bool DeviceDescriptor::PutBallast(fixed fraction, fixed overload, OperationEnvironment &env) { assert(InMainThread()); if (device == nullptr || !config.sync_to_device || (settings_sent.CompareBallastFraction(fraction) && settings_sent.CompareBallastOverload(overload))) return true; if (!Borrow()) /* TODO: postpone until the borrowed device has been returned */ return false; ScopeReturnDevice restore(*this, env); if (!device->PutBallast(fraction, overload, env)) return false; ScopeLock protect(device_blackboard->mutex); NMEAInfo &basic = device_blackboard->SetRealState(index); settings_sent.ballast_fraction = fraction; settings_sent.ballast_fraction_available.Update(basic.clock); settings_sent.ballast_overload = overload; settings_sent.ballast_overload_available.Update(basic.clock); return true; }
void ApplyVegaSwitches() { assert(InMainThread()); const VegaSwitchState &switches = CommonInterface::Basic().switch_state.vega; // detect changes to ON: on now (x) and not on before (!lastx) // detect changes to OFF: off now (!x) and on before (lastx) const unsigned up_inputs = switches.inputs & ~last_vega_switches.inputs; const unsigned down_inputs = ~switches.inputs & last_vega_switches.inputs; const unsigned up_outputs = switches.outputs & ~last_vega_switches.outputs; const unsigned down_outputs = ~switches.outputs & last_vega_switches.outputs; last_vega_switches = switches; for (unsigned i = 0; i < 32; ++i) { const unsigned thebit = 1 << i; if (down_inputs & thebit) InputEvents::processNmea(i); else if (up_inputs & thebit) InputEvents::processNmea(i + 64); if (down_outputs & thebit) InputEvents::processNmea(i + 32); else if (up_outputs & thebit) InputEvents::processNmea(i + 96); } }
void DeviceDescriptor::OnSysTicker() { assert(InMainThread()); if (port != nullptr && port->GetState() == PortState::FAILED && !IsOccupied()) Close(); if (device == nullptr) return; const bool now_alive = IsAlive(); if (!now_alive && was_alive && !IsOccupied()) { /* connection was just lost */ device->LinkTimeout(); NullOperationEnvironment env; EnableNMEA(env); } was_alive = now_alive; if (now_alive || IsBorrowed()) { ticker = !ticker; if (ticker) // write settings to vario every second device->OnSysTicker(); } }
void InputEvents::DoQueuedEvents() { assert(InMainThread()); int GCE_Queue_copy[MAX_GCE_QUEUE]; int i; // copy the queue first, blocking { const ScopeLock lock(mutexEventQueue); std::copy_n(GCE_Queue, MAX_GCE_QUEUE, GCE_Queue_copy); std::fill_n(GCE_Queue, MAX_GCE_QUEUE, -1); } // process each item in the queue for (i = 0; i < MAX_GCE_QUEUE; i++) { if (GCE_Queue_copy[i] != -1) { processGlideComputer_real(GCE_Queue_copy[i]); } } for (i = 0; i < MAX_NMEA_QUEUE; i++) { if (NMEA_Queue[i] != -1) processNmea_real(NMEA_Queue[i]); } }
void EnterDrawThread() { assert(InMainThread()); assert(draw_thread_handle == zero_thread_handle); draw_thread_handle = ThreadHandle::GetCurrent(); }
void LeaveDrawThread() { assert(InMainThread()); assert(draw_thread_handle.IsInside()); draw_thread_handle = zero_thread_handle; }
void DeviceDescriptor::Reopen(OperationEnvironment &env) { assert(InMainThread()); assert(!IsBorrowed()); Close(); Open(env); }
bool InDrawThread() { #ifdef ENABLE_OPENGL return InMainThread() && draw_thread_handle.IsInside(); #else return draw_thread != nullptr && draw_thread->IsInside(); #endif }
void DeviceDescriptor::OnCalculatedUpdate(const MoreData &basic, const DerivedInfo &calculated) { assert(InMainThread()); if (device != nullptr) device->OnCalculatedUpdate(basic, calculated); }
bool DeviceDescriptor::Borrow() { assert(InMainThread()); if (!CanBorrow()) return false; borrowed = true; return true; }
void DeviceDescriptor::OnNotification() { /* notification from AsyncJobRunner, the Job was finished */ assert(InMainThread()); assert(open_job != nullptr); async.Wait(); delete open_job; open_job = nullptr; }
void DeviceDescriptor::Return() { assert(InMainThread()); assert(IsBorrowed()); borrowed = false; assert(!IsOccupied()); /* if the caller has disabled the NMEA while the device was borrowed, we may not have received new values for some time, but that doesn't mean the device has failed; give it some time to recover, and don't reopen right away */ reopen_clock.Update(); }
bool InputEvents::processNmea(unsigned ne_id) { assert(InMainThread()); // add an event to the bottom of the queue for (int i = 0; i < MAX_NMEA_QUEUE; i++) { if (NMEA_Queue[i] == -1) { NMEA_Queue[i] = ne_id; break; } } return true; // ok. }
bool DeviceDescriptor::PutVolume(unsigned volume, OperationEnvironment &env) { assert(InMainThread()); if (device == nullptr || !config.sync_to_device) return true; if (!Borrow()) /* TODO: postpone until the borrowed device has been returned */ return false; ScopeReturnDevice restore(*this, env); return device->PutVolume(volume, env); }
bool DeviceDescriptor::PutStandbyFrequency(RadioFrequency frequency, OperationEnvironment &env) { assert(InMainThread()); if (device == NULL || !config.sync_to_device) return true; if (!Borrow()) /* TODO: postpone until the borrowed device has been returned */ return false; ScopeReturnDevice restore(*this, env); return device->PutStandbyFrequency(frequency, env); }
void DeviceDescriptor::CancelAsync() { assert(InMainThread()); if (!async.IsBusy()) return; assert(open_job != nullptr); async.Cancel(); async.Wait(); delete open_job; open_job = nullptr; }
void DeviceDescriptor::OnNotification() { /* notification from AsyncJobRunner, the Job was finished */ assert(InMainThread()); assert(open_job != nullptr); try { async.Wait(); } catch (const std::runtime_error &e) { LogError(e); } delete open_job; open_job = nullptr; }
void DeviceDescriptor::AutoReopen(OperationEnvironment &env) { assert(InMainThread()); if (/* don't reopen a device that is occupied */ IsOccupied() || !config.IsAvailable() || !ShouldReopen() || /* attempt to reopen a failed device every 30 seconds */ !reopen_clock.CheckUpdate(30000)) return; TCHAR buffer[64]; LogStartUp(_T("Reconnecting to device %s"), config.GetPortName(buffer, 64)); InputEvents::processGlideComputer(GCE_COMMPORT_RESTART); Reopen(env); }
void DeviceDescriptor::CancelAsync() { assert(InMainThread()); if (!async.IsBusy()) return; assert(open_job != nullptr); async.Cancel(); try { async.Wait(); } catch (const std::runtime_error &e) { LogError(e); } delete open_job; open_job = nullptr; }
void DeviceDescriptor::AutoReopen(OperationEnvironment &env) { assert(InMainThread()); if (/* don't reopen a device that is occupied */ IsOccupied() || !config.IsAvailable() || !ShouldReopen() || /* attempt to reopen a failed device every 30 seconds */ !reopen_clock.CheckUpdate(30000)) return; #ifdef ANDROID if (config.port_type == DeviceConfig::PortType::RFCOMM && android_api_level < 11 && n_failures >= 2) { /* on Android < 3.0, system_server's "BT EventLoop" thread eventually crashes with JNI reference table overflow due to a memory leak after too many Bluetooth failures (https://code.google.com/p/android/issues/detail?id=8676); don't attempt to reconnect on this Android version over and over to keep the chance of this bug occurring low enough */ if (n_failures == 2) { LogFormat(_T("Giving up on Bluetooth device %s to avoid Android crash bug"), config.bluetooth_mac.c_str()); ++n_failures; } return; } #endif TCHAR buffer[64]; LogFormat(_T("Reconnecting to device %s"), config.GetPortName(buffer, 64)); InputEvents::processGlideComputer(GCE_COMMPORT_RESTART); Reopen(env); }
void DeviceDescriptor::Open(OperationEnvironment &env) { assert(InMainThread()); assert(port == nullptr); assert(device == nullptr); assert(!ticker); assert(!IsBorrowed()); if (is_simulator() || !config.IsAvailable()) return; CancelAsync(); assert(!IsOccupied()); assert(open_job == nullptr); TCHAR buffer[64]; LogFormat(_T("Opening device %s"), config.GetPortName(buffer, 64)); open_job = new OpenDeviceJob(*this); async.Start(open_job, env, this); }
/** * Returns the InterfaceBlackboard.ComputerSettings (read-only) * @return The InterfaceBlackboard.ComputerSettings */ gcc_const static inline const ComputerSettings& GetComputerSettings() { assert(InMainThread()); return Private::blackboard.GetComputerSettings(); }
bool InDrawThread() { return InMainThread(); }
/** * Returns InterfaceBlackboard.Basic (NMEA_INFO) (read-only) * @return InterfaceBlackboard.Basic */ gcc_const static inline const MoreData &Basic() { assert(InMainThread()); return Private::blackboard.Basic(); }
/** * Returns InterfaceBlackboard.Calculated (DERIVED_INFO) (read-only) * @return InterfaceBlackboard.Calculated */ gcc_const static inline const DerivedInfo &Calculated() { assert(InMainThread()); return Private::blackboard.Calculated(); }
/** * Can this device be borrowed? * * May only be called from the main thread. * * @see Borrow() */ bool CanBorrow() const { assert(InMainThread()); return device != nullptr && GetState() == PortState::READY && !IsOccupied(); }
/** * Is this device currently occupied, i.e. does somebody have * exclusive access? * * May only be called from the main thread. */ bool IsOccupied() const { assert(InMainThread()); return IsBorrowed() || async.IsBusy(); }
gcc_const static inline SystemSettings &SetSystemSettings() { assert(InMainThread()); return Private::blackboard.SetSystemSettings(); }