39constexpr std::size_t kDcOutputCount = 4;
40constexpr std::size_t kUsbOutputCount = 6;
41constexpr std::size_t kHeaterCount = 2;
42constexpr unsigned kDcFirmwareBase = 2;
43constexpr unsigned kUsbFirmwareBase = 6;
44constexpr unsigned kHeaterFirmwareBase = 6;
46Result commandResult(
int rc,
bool connected,
bool communicationFailed)
64Result connectResult(
int rc,
bool cancellationObserved)
109 std::function<bool()> callback;
114 const bool cancelled = callback && callback();
156 switch (
state.load(std::memory_order_acquire))
177 std::shared_ptr<const TelemetrySnapshot>
snapshot()
const
186 return commandResult(rc,
211 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
216 impl_->invalidateTelemetry();
218 impl_->cancellationObserved.store(
false, std::memory_order_release);
219 const int rc = impl_->protocol.connect(port, settleMs);
220 Result result = connectResult(rc, impl_->cancellationObserved.load(std::memory_order_acquire));
223 impl_->invalidateTelemetry();
231 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
234 ConnectionState current = impl_->state.load(std::memory_order_acquire);
239 impl_->invalidateTelemetry();
241 impl_->cancellationObserved.store(
false, std::memory_order_release);
242 const int rc = impl_->protocol.reconnect();
243 Result result = connectResult(rc, impl_->cancellationObserved.load(std::memory_order_acquire));
246 impl_->invalidateTelemetry();
254 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
257 ConnectionState current = impl_->state.load(std::memory_order_acquire);
262 impl_->invalidateTelemetry();
263 impl_->protocol.disconnect();
270 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
273 Result ready = impl_->requireConnected();
274 if (!ready)
return ready;
275 return impl_->finishCommand(impl_->protocol.recoverStream());
280 return impl_->state.load(std::memory_order_acquire);
295 return impl_->protocol.registerTelemetryCallback(std::move(callback));
300 return impl_->protocol.removeTelemetryCallback(handle);
305 return impl_->protocol.registerConnectionCallback(std::move(callback));
310 return impl_->protocol.removeConnectionCallback(handle);
315 impl_->protocol.setInstrumentationLevel(level);
320 return impl_->protocol.instrumentationLevel();
325 return impl_->protocol.instrumentationEnabled(level);
330 return impl_->protocol.registerInstrumentationListener(std::move(listener));
335 return impl_->protocol.removeInstrumentationListener(handle);
340 std::lock_guard<std::mutex> lock(impl_->cancelMutex);
341 impl_->cancelFunction = std::move(callback);
347 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
349 Result ready = impl_->requireConnected();
350 if (!ready)
return ready;
351 return impl_->finishCommand(impl_->protocol.setOutput(
static_cast<unsigned>(kDcFirmwareBase + channel), enabled));
357 auto snapshot = impl_->snapshot();
365 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
367 Result ready = impl_->requireConnected();
368 if (!ready)
return ready;
369 return impl_->finishCommand(impl_->protocol.setOutput(
static_cast<unsigned>(kUsbFirmwareBase + channel), enabled));
375 auto snapshot = impl_->snapshot();
383 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
385 Result ready = impl_->requireConnected();
386 if (!ready)
return ready;
387 return impl_->finishCommand(impl_->protocol.setDewEnabled(
static_cast<unsigned>(kHeaterFirmwareBase + channel), enabled));
393 auto snapshot = impl_->snapshot();
403 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
405 Result ready = impl_->requireConnected();
406 if (!ready)
return ready;
407 return impl_->finishCommand(impl_->protocol.setDewMode(
static_cast<unsigned>(kHeaterFirmwareBase + channel), protocolMode));
413 auto snapshot = impl_->snapshot();
422 std::unique_lock<std::mutex> lifecycleLock(impl_->lifecycleMutex, std::try_to_lock);
424 Result ready = impl_->requireConnected();
425 if (!ready)
return ready;
427 Result result = impl_->finishCommand(impl_->protocol.setDewManualPercent(
static_cast<unsigned>
428 (kHeaterFirmwareBase + channel), percent));
431 std::lock_guard<std::mutex> lock(impl_->stateMutex);
432 impl_->heaterManualPower[channel] = percent;
433 impl_->haveHeaterManualPower[channel] =
true;
441 std::lock_guard<std::mutex> lock(impl_->stateMutex);
449 auto snapshot = impl_->snapshot();
456 auto snapshot = impl_->snapshot();
463 auto snapshot = impl_->snapshot();
470 auto snapshot = impl_->snapshot();
477 auto snapshot = impl_->snapshot();
484 auto snapshot = impl_->snapshot();
491 auto snapshot = impl_->snapshot();
498 auto snapshot = impl_->snapshot();
512void Device::injectStatusForTesting(
const StatusFrame &status)
514 impl_->protocol.injectStatusForTesting(status);
519 impl_->protocol.emitConnectionEventForTesting(event);
522void Device::setConnectedForTesting(
bool connected)
525 impl_->protocol.acceptingWrites_.store(connected, std::memory_order_release);
528std::size_t Device::queuedCommandCountForTesting()
const
530 return impl_->protocol.queuedCommandCountForTesting();
instrumentation::Dispatcher::ListenerHandle InstrumentationListenerHandle
void setInstrumentationLevel(instrumentation::Level level)
bool removeTelemetryCallback(TelemetryCallbackHandle handle)
TelemetryCallbackHandle registerTelemetryCallback(TelemetryCallback callback)
std::function< void(ConnectionEvent)> ConnectionCallback
ValueResult< bool > heaterEnabled(std::size_t channel) const
ConnectionCallbackHandle registerConnectionCallback(ConnectionCallback callback)
Result recoverTelemetryStream()
ConnectionState connectionState() const
bool removeInstrumentationListener(InstrumentationListenerHandle handle)
ValueResult< bool > usbOutputState(std::size_t channel) const
ValueResult< std::string > firmwareVersion() const
std::uint64_t TelemetryCallbackHandle
bool hasCommunicationFailure() const
std::uint64_t ConnectionCallbackHandle
instrumentation::Level instrumentationLevel() const
ValueResult< HeaterMode > heaterMode(std::size_t channel) const
ValueResult< double > inputCurrent() const
Result setHeaterEnabled(std::size_t channel, bool enabled)
Result setHeaterManualPower(std::size_t channel, unsigned percent)
InstrumentationListenerHandle registerInstrumentationListener(InstrumentationListener listener)
ValueResult< double > heaterCurrentOutput(std::size_t channel) const
ValueResult< double > dewPoint() const
ValueResult< unsigned > heaterManualPower(std::size_t channel) const
ValueResult< double > airTemperature() const
Result setHeaterMode(std::size_t channel, HeaterMode mode)
instrumentation::Dispatcher::Listener InstrumentationListener
ValueResult< double > deviceSurfaceTemperature() const
ValueResult< double > inputVoltage() const
void setCancelFunction(std::function< bool()> callback)
ValueResult< double > humidity() const
bool removeConnectionCallback(ConnectionCallbackHandle handle)
Result setUsbOutput(std::size_t channel, bool enabled)
Result connect(const std::string &port, int settleMs=0)
ValueResult< double > inputPower() const
std::function< void(const TelemetrySnapshot &)> TelemetryCallback
ValueResult< bool > dcOutputState(std::size_t channel) const
Result setDcOutput(std::size_t channel, bool enabled)
bool instrumentationEnabled(instrumentation::Level level) const
void setCancelFunction(std::function< bool()> fn)
std::uint64_t TelemetryCallbackHandle
TelemetryCallbackHandle registerTelemetryCallback(TelemetryCallback callback)
bool removeTelemetryCallback(TelemetryCallbackHandle handle)
std::uint64_t ConnectionCallbackHandle
bool removeConnectionCallback(ConnectionCallbackHandle handle)
ConnectionCallbackHandle registerConnectionCallback(ConnectionCallback callback)
static constexpr Result failure(Error error)
static constexpr Result success()
static ValueResult failure(Error error)
std::mutex lifecycleMutex
std::array< unsigned, kHeaterCount > heaterManualPower
std::shared_ptr< const TelemetrySnapshot > snapshot() const
void invalidateTelemetry()
GeminiProtocol::ConnectionCallbackHandle internalConnectionCallback_
GeminiProtocol::TelemetryCallbackHandle internalTelemetryCallback_
std::atomic< bool > cancellationObserved
std::array< bool, kHeaterCount > haveHeaterManualPower
Result finishCommand(int rc) const
std::function< bool()> cancelFunction
std::shared_ptr< const TelemetrySnapshot > latestTelemetry
std::atomic< ConnectionState > state
Result requireConnected() const