Instrument Neutral Distributed Interface INDI 2.2.5
indi_gemini_pbh.h
Go to the documentation of this file.
1/*
2 Gemini Power Box Hub Advanced v3 INDI Driver
3
4 Copyright (C) 2026 Dieter R Kedrowitsch <[email protected]>
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 The full GNU General Public License is included in this distribution in the
21 file called LICENSE.
22*/
23
24#pragma once
25
26#include <array>
27#include <atomic>
28#include <chrono>
29#include <cstddef>
30#include <deque>
31#include <memory>
32#include <mutex>
33#include <optional>
34#include <string>
35#include <vector>
36
37#include <defaultdevice.h>
38#include <indipowerinterface.h>
39#include <indipropertynumber.h>
40#include <indipropertyswitch.h>
41#include <indipropertytext.h>
42
47
48#include "driver_support.h"
49
50namespace Connection
51{
52class Serial;
53}
54
56{
57 public:
58 GeminiPBH();
59 ~GeminiPBH() override;
60
61 bool initProperties() override;
62 bool updateProperties() override;
63 bool Connect() override;
64 bool Disconnect() override;
65 void TimerHit() override;
66 void debugTriggered(bool enable) override;
67
68 bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override;
69 bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override;
70 bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override;
71
72 protected:
73 const char *getDefaultName() override;
74 bool saveConfigItems(FILE *fp) override;
75
76 bool SetPowerPort(size_t port, bool enabled) override;
77 bool SetDewPort(size_t port, bool enabled, double dutyCycle) override;
78 bool SetUSBPort(size_t port, bool enabled) override;
79
80#ifdef GEMINI_TESTING
81 public:
82 void simulateConnectedTelemetryForTesting(const geminipbh::TelemetrySnapshot &snapshot);
83 void checkTelemetryFreshnessForTesting(std::chrono::steady_clock::time_point now);
84 bool communicationFailureForTesting() const;
85 IPState powerSensorsStateForTesting() const;
86 IPState environmentStateForTesting() const;
87 IPState powerChannelsStateForTesting() const;
88 IPState dewModeStateForTesting(size_t index) const;
89 void simulateHeaterModePendingForTesting(size_t heaterIndex, geminipbh::HeaterMode targetMode,
90 std::chrono::steady_clock::time_point deadline);
91 void checkPendingOperationsForTesting(const geminipbh::TelemetrySnapshot &snapshot);
92 geminipbh::instrumentation::Level instrumentationLevelForTesting() const;
93 void syncInstrumentationLevelForTesting();
94 void setDebugForTesting(bool enable);
95 void setSerialPortForTesting(const std::string &port);
96 std::string serialPortForTesting() const;
97 void setAutoSearchForTesting(bool enabled);
98 void setDiscoveryFunctionForTesting(std::function<geminipbh::DiscoveryResult()> fn);
99 bool detectedPortSaveRequestedForTesting() const;
100#endif
101
102 private:
103 enum class DriverState
104 {
105 Disconnected,
106 Connecting,
107 Connected,
108 CommunicationFailure,
109 Reconnecting
110 };
111
112 void initializePowerInterfaceProperties();
113 void initializeCustomProperties();
114 void defineConnectedProperties();
115 void deleteConnectedProperties();
116 void refreshLabelsFromTextProperties();
117 bool finishSuccessfulConnection(bool detectedPort);
118
119 bool autoSearchEnabled() const;
120 bool updateSerialPortSelection(const std::string &port);
121 bool discoveryCancellationRequested() const;
122 geminipbh::DiscoveryResult runDiscovery();
123 std::vector<geminipbh::ProbeResult> supportedDiscoveryDevices(const geminipbh::DiscoveryResult &discovery) const;
124 bool isSupportedDiscoveryDevice(const geminipbh::ProbeResult &device, std::string &reason) const;
125
126 bool handlePowerSwitchChange(INDI::PropertySwitch &property, ISState *states, char *names[], int n,
128 bool handleDewModeChange(size_t heaterIndex, INDI::PropertySwitch &property, ISState *states,
129 char *names[], int n);
130 bool handleDewDutyCycleChange(double values[], char *names[], int n);
131
132 void registerDeviceCallbacks();
133 void removeDeviceCallbacks();
134 void handleTelemetry(const geminipbh::TelemetrySnapshot &snapshot);
135 void handleConnectionEvent(geminipbh::ConnectionEvent event);
136 void handleInstrumentation(const geminipbh::instrumentation::Event &event);
137 void syncInstrumentationLevelWithIndiDebug();
138 void flushConnectionEvents();
139 void processConnectionEvent(geminipbh::ConnectionEvent event);
140 void flushTelemetryToINDI();
141 void refreshPropertiesFromDevice();
142 void checkTelemetryFreshness();
143 void checkTelemetryFreshness(std::chrono::steady_clock::time_point now);
144 void checkPendingOperations();
145 void checkPendingOperations(const geminipbh::TelemetrySnapshot *snapshot);
146 void attemptReconnectIfDue();
147 void markCommunicationFailure(const std::string &reason);
148 void markHardwareProperties(IPState state);
149 void failPendingOperations(IPState state);
150 void scheduleNextTimer();
151
152 bool requestDcOutputChange(size_t port, bool enabled);
153 bool requestUsbOutputChange(size_t port, bool enabled);
154 bool requestHeaterEnabledChange(size_t port, bool enabled);
155 bool requestHeaterModeChange(size_t port, geminipbh::HeaterMode mode);
156 bool requestHeaterManualPowerChange(size_t port, double percent);
157 geminipbh::Result requireWriteReady() const;
158 void addPendingOperation(geminipbh::indi_driver::PendingOperation operation);
159 bool hasPendingOperation(geminipbh::indi_driver::PendingOperationKind kind) const;
160 bool hasPendingOperation(geminipbh::indi_driver::PendingOperationKind kind, size_t index) const;
161 void applyPendingAwareLiveStates();
162 void logDeviceError(const char *action, geminipbh::Error error) const;
163
164 static const char *heaterModeName(geminipbh::HeaterMode mode);
165
166 INDI::PropertyText DeviceInfoTP {1};
167 INDI::PropertyNumber EnvironmentNP {4};
168 INDI::PropertySwitch Dew1ModeSP {3};
169 INDI::PropertySwitch Dew2ModeSP {3};
170 INDI::PropertyNumber DewOutputsNP {2};
171
172 std::unique_ptr<geminipbh::Device> device_;
173 geminipbh::Device::TelemetryCallbackHandle telemetryCallbackHandle_ = 0;
174 geminipbh::Device::ConnectionCallbackHandle connectionCallbackHandle_ = 0;
175 geminipbh::Device::InstrumentationListenerHandle instrumentationListenerHandle_ = 0;
176 std::unique_ptr<Connection::Serial> serialConnection_;
177
178#ifdef GEMINI_TESTING
179 std::optional<bool> autoSearchOverrideForTesting_;
180 std::function<geminipbh::DiscoveryResult()> discoveryFunctionForTesting_;
181 bool detectedPortSaveRequestedForTesting_ = false;
182#endif
183
185 std::atomic<bool> protocolInstrumentationForwarding_{false};
186 bool haveTelemetry_ = false;
187 std::atomic<bool> shutdownInProgress_{false};
188
189 DriverState driverState_ = DriverState::Disconnected;
190 bool userDisconnectRequested_ = true;
191 bool connectedPropertiesDefined_ = false;
192
193 std::array<unsigned, 2> preservedManualPower_{{0, 0}};
194 std::vector<geminipbh::indi_driver::PendingOperation> pendingOperations_;
195 std::chrono::steady_clock::time_point lastReconnectAttempt_{};
196 std::chrono::steady_clock::time_point lastTelemetryTime_{};
197};
hid_device * device
~GeminiPBH() override
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
bool SetPowerPort(size_t port, bool enabled) override
SetPowerPort Set power port on/off.
const char * getDefaultName() override
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
bool Disconnect() override
Disconnect from device.
void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
instrumentation::Dispatcher::ListenerHandle InstrumentationListenerHandle
Definition device.h:59
std::uint64_t TelemetryCallbackHandle
Definition device.h:55
std::uint64_t ConnectionCallbackHandle
Definition device.h:57
ISState
Switch state.
Definition indiapi.h:148
IPState
Property state.
Definition indiapi.h:158
Combines all INDI Connection Plugins. Each INDI connection plugin is responsible of managing communic...
Definition arduino_st4.h:34