1 /*******************************************************************************
2 Copyright(c) 2018 Jasem Mutlaq. All rights reserved.
3
4 Pegasus Ultimate Power Box Driver.
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 Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 The full GNU General Public License is included in this distribution in the
22 file called LICENSE.
23 *******************************************************************************/
24
25 #include "pegasus_upb.h"
26 #include "indicom.h"
27 #include "connectionplugins/connectionserial.h"
28
29 #include <memory>
30 #include <regex>
31 #include <termios.h>
32 #include <cstring>
33 #include <sys/ioctl.h>
34 #include <chrono>
35 #include <math.h>
36 #include <iomanip>
37
38 // We declare an auto pointer to PegasusUPB.
39 static std::unique_ptr<PegasusUPB> upb(new PegasusUPB());
40
PegasusUPB()41 PegasusUPB::PegasusUPB() : FI(this), WI(this)
42 {
43 setVersion(1, 6);
44
45 lastSensorData.reserve(21);
46 lastPowerData.reserve(4);
47 lastStepperData.reserve(4);
48 lastDewAggData.reserve(1);
49 }
50
initProperties()51 bool PegasusUPB::initProperties()
52 {
53 INDI::DefaultDevice::initProperties();
54
55 setDriverInterface(AUX_INTERFACE | FOCUSER_INTERFACE | WEATHER_INTERFACE);
56
57 FI::SetCapability(FOCUSER_CAN_ABS_MOVE |
58 FOCUSER_CAN_REL_MOVE |
59 FOCUSER_CAN_REVERSE |
60 FOCUSER_CAN_SYNC |
61 FOCUSER_CAN_ABORT |
62 FOCUSER_HAS_BACKLASH);
63
64 FI::initProperties(FOCUS_TAB);
65 WI::initProperties(ENVIRONMENT_TAB, ENVIRONMENT_TAB);
66
67 addAuxControls();
68
69 ////////////////////////////////////////////////////////////////////////////
70 /// Main Control Panel
71 ////////////////////////////////////////////////////////////////////////////
72 // Cycle all power on/off
73 IUFillSwitch(&PowerCycleAllS[POWER_CYCLE_ON], "POWER_CYCLE_ON", "All On", ISS_OFF);
74 IUFillSwitch(&PowerCycleAllS[POWER_CYCLE_OFF], "POWER_CYCLE_OFF", "All Off", ISS_OFF);
75 IUFillSwitchVector(&PowerCycleAllSP, PowerCycleAllS, 2, getDeviceName(), "POWER_CYCLE", "Cycle Power", MAIN_CONTROL_TAB,
76 IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
77
78 // Reboot
79 IUFillSwitch(&RebootS[0], "REBOOT", "Reboot Device", ISS_OFF);
80 IUFillSwitchVector(&RebootSP, RebootS, 1, getDeviceName(), "REBOOT_DEVICE", "Device", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1,
81 60, IPS_IDLE);
82
83 // Power Sensors
84 IUFillNumber(&PowerSensorsN[SENSOR_VOLTAGE], "SENSOR_VOLTAGE", "Voltage (V)", "%4.2f", 0, 999, 100, 0);
85 IUFillNumber(&PowerSensorsN[SENSOR_CURRENT], "SENSOR_CURRENT", "Current (A)", "%4.2f", 0, 999, 100, 0);
86 IUFillNumber(&PowerSensorsN[SENSOR_POWER], "SENSOR_POWER", "Power (W)", "%4.2f", 0, 999, 100, 0);
87 IUFillNumberVector(&PowerSensorsNP, PowerSensorsN, 3, getDeviceName(), "POWER_SENSORS", "Sensors", MAIN_CONTROL_TAB, IP_RO,
88 60, IPS_IDLE);
89
90 // Overall Power Consumption
91 IUFillNumber(&PowerConsumptionN[CONSUMPTION_AVG_AMPS], "CONSUMPTION_AVG_AMPS", "Avg. Amps", "%4.2f", 0, 999, 100, 0);
92 IUFillNumber(&PowerConsumptionN[CONSUMPTION_AMP_HOURS], "CONSUMPTION_AMP_HOURS", "Amp Hours", "%4.2f", 0, 999, 100, 0);
93 IUFillNumber(&PowerConsumptionN[CONSUMPTION_WATT_HOURS], "CONSUMPTION_WATT_HOURS", "Watt Hours", "%4.2f", 0, 999, 100, 0);
94 IUFillNumberVector(&PowerConsumptionNP, PowerConsumptionN, 3, getDeviceName(), "POWER_CONSUMPTION", "Consumption",
95 MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
96
97 ////////////////////////////////////////////////////////////////////////////
98 /// Power Group
99 ////////////////////////////////////////////////////////////////////////////
100
101 // Dew Labels. Need to delare them here to use in the Power usage section
102 IUFillText(&DewControlsLabelsT[0], "DEW_LABEL_1", "Dew A", "Dew A");
103 IUFillText(&DewControlsLabelsT[1], "DEW_LABEL_2", "Dew B", "Dew B");
104 IUFillText(&DewControlsLabelsT[2], "DEW_LABEL_3", "Dew C", "Dew C");
105 IUFillTextVector(&DewControlsLabelsTP, DewControlsLabelsT, 3, getDeviceName(), "DEW_CONTROL_LABEL", "Dew Labels",
106 DEW_TAB, IP_WO, 60, IPS_IDLE);
107
108 char dewLabel[MAXINDILABEL];
109
110 // Turn on/off power and power boot up
111 memset(dewLabel, 0, MAXINDILABEL);
112 int dewRC = IUGetConfigText(getDeviceName(), DewControlsLabelsTP.name, DewControlsLabelsT[0].name, dewLabel,
113 MAXINDILABEL);
114 IUFillSwitch(&AutoDewV2S[DEW_PWM_A], "DEW_A", dewRC == -1 ? "Dew A" : dewLabel, ISS_OFF);
115 memset(dewLabel, 0, MAXINDILABEL);
116 dewRC = IUGetConfigText(getDeviceName(), DewControlsLabelsTP.name, DewControlsLabelsT[1].name, dewLabel,
117 MAXINDILABEL);
118 IUFillSwitch(&AutoDewV2S[DEW_PWM_B], "DEW_B", dewRC == -1 ? "Dew B" : dewLabel, ISS_OFF);
119 memset(dewLabel, 0, MAXINDILABEL);
120 dewRC = IUGetConfigText(getDeviceName(), DewControlsLabelsTP.name, DewControlsLabelsT[2].name, dewLabel,
121 MAXINDILABEL);
122 IUFillSwitch(&AutoDewV2S[DEW_PWM_C], "DEW_C", dewRC == -1 ? "Dew C" : dewLabel, ISS_OFF);
123 IUFillSwitchVector(&AutoDewV2SP, AutoDewV2S, 3, getDeviceName(), "AUTO_DEW", "Auto Dew", DEW_TAB, IP_RW, ISR_NOFMANY, 60,
124 IPS_IDLE);
125
126 // Dew Labels with custom labels
127 IUFillText(&DewControlsLabelsT[0], "DEW_LABEL_1", "Dew A", AutoDewV2S[0].label);
128 IUFillText(&DewControlsLabelsT[1], "DEW_LABEL_2", "Dew B", AutoDewV2S[1].label);
129 IUFillText(&DewControlsLabelsT[2], "DEW_LABEL_3", "Dew C", AutoDewV2S[2].label);
130 IUFillTextVector(&DewControlsLabelsTP, DewControlsLabelsT, 3, getDeviceName(), "DEW_CONTROL_LABEL", "DEW Labels",
131 DEW_TAB, IP_WO, 60, IPS_IDLE);
132 // Power Labels
133 IUFillText(&PowerControlsLabelsT[0], "POWER_LABEL_1", "Port 1", "Port 1");
134 IUFillText(&PowerControlsLabelsT[1], "POWER_LABEL_2", "Port 2", "Port 2");
135 IUFillText(&PowerControlsLabelsT[2], "POWER_LABEL_3", "Port 3", "Port 3");
136 IUFillText(&PowerControlsLabelsT[3], "POWER_LABEL_4", "Port 4", "Port 4");
137 IUFillTextVector(&PowerControlsLabelsTP, PowerControlsLabelsT, 4, getDeviceName(), "POWER_CONTROL_LABEL", "Power Labels",
138 POWER_TAB, IP_WO, 60, IPS_IDLE);
139
140 char portLabel[MAXINDILABEL];
141
142 // Turn on/off power and power boot up
143 memset(portLabel, 0, MAXINDILABEL);
144 int portRC = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[0].name, portLabel,
145 MAXINDILABEL);
146 IUFillSwitch(&PowerControlS[0], "POWER_CONTROL_1", portRC == -1 ? "Port 1" : portLabel, ISS_OFF);
147
148 memset(portLabel, 0, MAXINDILABEL);
149 portRC = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[1].name, portLabel,
150 MAXINDILABEL);
151 IUFillSwitch(&PowerControlS[1], "POWER_CONTROL_2", portRC == -1 ? "Port 2" : portLabel, ISS_OFF);
152
153 memset(portLabel, 0, MAXINDILABEL);
154 portRC = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[2].name, portLabel,
155 MAXINDILABEL);
156 IUFillSwitch(&PowerControlS[2], "POWER_CONTROL_3", portRC == -1 ? "Port 3" : portLabel, ISS_OFF);
157
158 memset(portLabel, 0, MAXINDILABEL);
159 portRC = IUGetConfigText(getDeviceName(), PowerControlsLabelsTP.name, PowerControlsLabelsT[3].name, portLabel,
160 MAXINDILABEL);
161 IUFillSwitch(&PowerControlS[3], "POWER_CONTROL_4", portRC == -1 ? "Port 4" : portLabel, ISS_OFF);
162
163 IUFillSwitchVector(&PowerControlSP, PowerControlS, 4, getDeviceName(), "POWER_CONTROL", "Power Control", POWER_TAB, IP_RW,
164 ISR_NOFMANY, 60, IPS_IDLE);
165
166 // Power Labels
167 IUFillText(&PowerControlsLabelsT[0], "POWER_LABEL_1", "Port 1", PowerControlS[0].label);
168 IUFillText(&PowerControlsLabelsT[1], "POWER_LABEL_2", "Port 2", PowerControlS[1].label);
169 IUFillText(&PowerControlsLabelsT[2], "POWER_LABEL_3", "Port 3", PowerControlS[2].label);
170 IUFillText(&PowerControlsLabelsT[3], "POWER_LABEL_4", "Port 4", PowerControlS[3].label);
171 IUFillTextVector(&PowerControlsLabelsTP, PowerControlsLabelsT, 4, getDeviceName(), "POWER_CONTROL_LABEL", "Power Labels",
172 POWER_TAB, IP_WO, 60, IPS_IDLE);
173
174 // Current Draw
175 IUFillNumber(&PowerCurrentN[0], "POWER_CURRENT_1", PowerControlS[0].label, "%4.2f A", 0, 1000, 0, 0);
176 IUFillNumber(&PowerCurrentN[1], "POWER_CURRENT_2", PowerControlS[1].label, "%4.2f A", 0, 1000, 0, 0);
177 IUFillNumber(&PowerCurrentN[2], "POWER_CURRENT_3", PowerControlS[2].label, "%4.2f A", 0, 1000, 0, 0);
178 IUFillNumber(&PowerCurrentN[3], "POWER_CURRENT_4", PowerControlS[3].label, "%4.2f A", 0, 1000, 0, 0);
179 IUFillNumberVector(&PowerCurrentNP, PowerCurrentN, 4, getDeviceName(), "POWER_CURRENT", "Current Draw", POWER_TAB, IP_RO,
180 60, IPS_IDLE);
181
182 // Power on Boot
183 IUFillSwitch(&PowerOnBootS[0], "POWER_PORT_1", PowerControlS[0].label, ISS_ON);
184 IUFillSwitch(&PowerOnBootS[1], "POWER_PORT_2", PowerControlS[1].label, ISS_ON);
185 IUFillSwitch(&PowerOnBootS[2], "POWER_PORT_3", PowerControlS[2].label, ISS_ON);
186 IUFillSwitch(&PowerOnBootS[3], "POWER_PORT_4", PowerControlS[3].label, ISS_ON);
187 IUFillSwitchVector(&PowerOnBootSP, PowerOnBootS, 4, getDeviceName(), "POWER_ON_BOOT", "Power On Boot", POWER_TAB, IP_RW,
188 ISR_NOFMANY, 60, IPS_IDLE);
189
190 // Over Current
191 IUFillLight(&OverCurrentL[0], "POWER_PORT_1", PowerControlS[0].label, IPS_OK);
192 IUFillLight(&OverCurrentL[1], "POWER_PORT_2", PowerControlS[1].label, IPS_OK);
193 IUFillLight(&OverCurrentL[2], "POWER_PORT_3", PowerControlS[2].label, IPS_OK);
194 IUFillLight(&OverCurrentL[3], "POWER_PORT_4", PowerControlS[3].label, IPS_OK);
195
196 char tempLabel[MAXINDILABEL + 5];
197 memset(tempLabel, 0, MAXINDILABEL + 5);
198 sprintf(tempLabel, "%s %s", "Dew:", AutoDewV2S[0].label);
199 IUFillLight(&OverCurrentL[4], "DEW_A", tempLabel, IPS_OK);
200 memset(tempLabel, 0, MAXINDILABEL);
201 sprintf(tempLabel, "%s %s", "Dew:", AutoDewV2S[1].label);
202 IUFillLight(&OverCurrentL[5], "DEW_B", tempLabel, IPS_OK);
203 memset(tempLabel, 0, MAXINDILABEL);
204 sprintf(tempLabel, "%s %s", "Dew:", AutoDewV2S[2].label);
205 IUFillLight(&OverCurrentL[6], "DEW_C", tempLabel, IPS_OK);
206 IUFillLightVector(&OverCurrentLP, OverCurrentL, 7, getDeviceName(), "POWER_OVER_CURRENT", "Over Current", POWER_TAB,
207 IPS_IDLE);
208
209 // Power LED
210 IUFillSwitch(&PowerLEDS[POWER_LED_ON], "POWER_LED_ON", "On", ISS_ON);
211 IUFillSwitch(&PowerLEDS[POWER_LED_OFF], "POWER_LED_OFF", "Off", ISS_OFF);
212 IUFillSwitchVector(&PowerLEDSP, PowerLEDS, 2, getDeviceName(), "POWER_LED", "LED", POWER_TAB, IP_RW, ISR_1OFMANY, 60,
213 IPS_IDLE);
214
215 IUFillNumber(&AdjustableOutputN[0], "ADJUSTABLE_VOLTAGE_VALUE", "Voltage (V)", "%.f", 3, 12, 1, 12);
216 IUFillNumberVector(&AdjustableOutputNP, AdjustableOutputN, 1, getDeviceName(), "ADJUSTABLE_VOLTAGE", "Adj. Output",
217 POWER_TAB, IP_RW, 60, IPS_IDLE);
218
219
220 ////////////////////////////////////////////////////////////////////////////
221 /// Dew Group
222 ////////////////////////////////////////////////////////////////////////////
223
224 // Automatic Dew v1
225 IUFillSwitch(&AutoDewS[INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
226 IUFillSwitch(&AutoDewS[INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_ON);
227 IUFillSwitchVector(&AutoDewSP, AutoDewS, 2, getDeviceName(), "AUTO_DEW", "Auto Dew", DEW_TAB, IP_RW, ISR_1OFMANY, 60,
228 IPS_IDLE);
229
230 // Automatic Dew Aggressiveness v2
231 IUFillNumber(&AutoDewAggN[AUTO_DEW_AGG], "AUTO_DEW_AGG_VALUE", "Auto Dew Agg (50-250)", "%.2f", 50, 250, 20, 0);
232 IUFillNumberVector(&AutoDewAggNP, AutoDewAggN, 1, getDeviceName(), "AUTO_DEW_AGG", "Auto Dew Agg", DEW_TAB, IP_RW, 60,
233 IPS_IDLE);
234
235 // Dew PWM
236 IUFillNumber(&DewPWMN[DEW_PWM_A], "DEW_A", AutoDewV2S[0].label, "%.2f %%", 0, 100, 10, 0);
237 IUFillNumber(&DewPWMN[DEW_PWM_B], "DEW_B", AutoDewV2S[1].label, "%.2f %%", 0, 100, 10, 0);
238 IUFillNumber(&DewPWMN[DEW_PWM_C], "DEW_C", AutoDewV2S[2].label, "%.2f %%", 0, 100, 10, 0);
239 IUFillNumberVector(&DewPWMNP, DewPWMN, 3, getDeviceName(), "DEW_PWM", "Dew PWM", DEW_TAB, IP_RW, 60, IPS_IDLE);
240
241 // Dew current draw
242 IUFillNumber(&DewCurrentDrawN[DEW_PWM_A], "DEW_CURRENT_A", AutoDewV2S[0].label, "%4.2f A", 0, 1000, 10, 0);
243 IUFillNumber(&DewCurrentDrawN[DEW_PWM_B], "DEW_CURRENT_B", AutoDewV2S[1].label, "%4.2f A", 0, 1000, 10, 0);
244 IUFillNumber(&DewCurrentDrawN[DEW_PWM_C], "DEW_CURRENT_C", AutoDewV2S[2].label, "%4.2f A", 0, 1000, 10, 0);
245 IUFillNumberVector(&DewCurrentDrawNP, DewCurrentDrawN, 3, getDeviceName(), "DEW_CURRENT", "Dew Current", DEW_TAB, IP_RO, 60,
246 IPS_IDLE);
247
248 ////////////////////////////////////////////////////////////////////////////
249 /// USB Group
250 ////////////////////////////////////////////////////////////////////////////
251
252 // USB Hub control v1
253 IUFillSwitch(&USBControlS[INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_ON);
254 IUFillSwitch(&USBControlS[INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_OFF);
255 IUFillSwitchVector(&USBControlSP, USBControlS, 2, getDeviceName(), "USB_HUB_CONTROL", "Hub", USB_TAB, IP_RW, ISR_1OFMANY,
256 60, IPS_IDLE);
257
258 // USB Labels
259 IUFillText(&USBControlsLabelsT[0], "USB_LABEL_1", "USB3 Port1", "USB3 Port1");
260 IUFillText(&USBControlsLabelsT[1], "USB_LABEL_2", "USB3 Port2", "USB3 Port2");
261 IUFillText(&USBControlsLabelsT[2], "USB_LABEL_3", "USB3 Port3", "USB3 Port3");
262 IUFillText(&USBControlsLabelsT[3], "USB_LABEL_4", "USB3 Port4", "USB3 Port4");
263 IUFillText(&USBControlsLabelsT[4], "USB_LABEL_5", "USB2 Port5", "USB2 Port5");
264 IUFillText(&USBControlsLabelsT[5], "USB_LABEL_6", "USB2 Port6", "USB2 Port6");
265
266 IUFillTextVector(&USBControlsLabelsTP, USBControlsLabelsT, 6, getDeviceName(), "USB_CONTROL_LABEL", "USB Labels",
267 USB_TAB, IP_WO, 60, IPS_IDLE);
268
269 // USB Hub control v2
270
271 char USBLabel[MAXINDILABEL];
272
273 // Turn on/off power and power boot up
274 memset(USBLabel, 0, MAXINDILABEL);
275 int USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[0].name, USBLabel,
276 MAXINDILABEL);
277 IUFillSwitch(&USBControlV2S[0], "PORT_1", USBRC == -1 ? "USB3 Port1" : USBLabel, ISS_ON);
278 memset(USBLabel, 0, MAXINDILABEL);
279 USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[1].name, USBLabel,
280 MAXINDILABEL);
281 IUFillSwitch(&USBControlV2S[1], "PORT_2", USBRC == -1 ? "USB3 Port2" : USBLabel, ISS_ON);
282 memset(USBLabel, 0, MAXINDILABEL);
283 USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[2].name, USBLabel,
284 MAXINDILABEL);
285 IUFillSwitch(&USBControlV2S[2], "PORT_3", USBRC == -1 ? "USB3 Port3" : USBLabel, ISS_ON);
286 memset(USBLabel, 0, MAXINDILABEL);
287 USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[3].name, USBLabel,
288 MAXINDILABEL);
289 IUFillSwitch(&USBControlV2S[3], "PORT_4", USBRC == -1 ? "USB3 Port4" : USBLabel, ISS_ON);
290 memset(USBLabel, 0, MAXINDILABEL);
291 USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[4].name, USBLabel,
292 MAXINDILABEL);
293 IUFillSwitch(&USBControlV2S[4], "PORT_5", USBRC == -1 ? "USB2 Port5" : USBLabel, ISS_ON);
294 memset(USBLabel, 0, MAXINDILABEL);
295 USBRC = IUGetConfigText(getDeviceName(), USBControlsLabelsTP.name, USBControlsLabelsT[5].name, USBLabel,
296 MAXINDILABEL);
297 IUFillSwitch(&USBControlV2S[5], "PORT_6", USBRC == -1 ? "USB2 Port6" : USBLabel, ISS_ON);
298
299 IUFillSwitchVector(&USBControlV2SP, USBControlV2S, 6, getDeviceName(), "USB_PORT_CONTROL", "Ports", USB_TAB, IP_RW,
300 ISR_NOFMANY, 60, IPS_IDLE);
301
302 // USB Labels update with custom values
303 IUFillText(&USBControlsLabelsT[0], "USB_LABEL_1", "USB3 Port1", USBControlV2S[0].label);
304 IUFillText(&USBControlsLabelsT[1], "USB_LABEL_2", "USB3 Port2", USBControlV2S[1].label);
305 IUFillText(&USBControlsLabelsT[2], "USB_LABEL_3", "USB3 Port3", USBControlV2S[2].label);
306 IUFillText(&USBControlsLabelsT[3], "USB_LABEL_4", "USB3 Port4", USBControlV2S[3].label);
307 IUFillText(&USBControlsLabelsT[4], "USB_LABEL_5", "USB2 Port5", USBControlV2S[4].label);
308 IUFillText(&USBControlsLabelsT[5], "USB_LABEL_6", "USB2 Port6", USBControlV2S[5].label);
309
310 IUFillTextVector(&USBControlsLabelsTP, USBControlsLabelsT, 6, getDeviceName(), "USB_CONTROL_LABEL", "USB Labels",
311 USB_TAB, IP_WO, 60, IPS_IDLE);
312 // USB Hub Status
313 IUFillLight(&USBStatusL[0], "PORT_1", USBControlV2S[0].label, IPS_OK);
314 IUFillLight(&USBStatusL[1], "PORT_2", USBControlV2S[1].label, IPS_OK);
315 IUFillLight(&USBStatusL[2], "PORT_3", USBControlV2S[2].label, IPS_OK);
316 IUFillLight(&USBStatusL[3], "PORT_4", USBControlV2S[3].label, IPS_OK);
317 IUFillLight(&USBStatusL[4], "PORT_5", USBControlV2S[4].label, IPS_OK);
318 IUFillLight(&USBStatusL[5], "PORT_6", USBControlV2S[5].label, IPS_OK);
319 IUFillLightVector(&USBStatusLP, USBStatusL, 6, getDeviceName(), "USB_PORT_STATUS", "Status", USB_TAB, IPS_IDLE);
320
321 ////////////////////////////////////////////////////////////////////////////
322 /// Focuser Group
323 ////////////////////////////////////////////////////////////////////////////
324
325 // Settings
326 // IUFillNumber(&FocusBacklashN[0], "SETTING_BACKLASH", "Backlash (steps)", "%.f", 0, 999, 100, 0);
327 IUFillNumber(&FocuserSettingsN[SETTING_MAX_SPEED], "SETTING_MAX_SPEED", "Max Speed (%)", "%.f", 0, 900, 100, 400);
328 IUFillNumberVector(&FocuserSettingsNP, FocuserSettingsN, 1, getDeviceName(), "FOCUSER_SETTINGS", "Settings", FOCUS_TAB,
329 IP_RW, 60, IPS_IDLE);
330 ////////////////////////////////////////////////////////////////////////////
331 /// Firmware Group
332 ////////////////////////////////////////////////////////////////////////////
333 IUFillText(&FirmwareT[FIRMWARE_VERSION], "VERSION", "Version", "NA");
334 IUFillText(&FirmwareT[FIRMWARE_UPTIME], "UPTIME", "Uptime (h)", "NA");
335 IUFillTextVector(&FirmwareTP, FirmwareT, 2, getDeviceName(), "FIRMWARE_INFO", "Firmware", FIRMWARE_TAB, IP_RO, 60,
336 IPS_IDLE);
337 ////////////////////////////////////////////////////////////////////////////
338 /// Environment Group
339 ////////////////////////////////////////////////////////////////////////////
340 addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
341 addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
342 addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
343 setCriticalParameter("WEATHER_TEMPERATURE");
344
345 ////////////////////////////////////////////////////////////////////////////
346 /// Serial Connection
347 ////////////////////////////////////////////////////////////////////////////
348 serialConnection = new Connection::Serial(this);
349 serialConnection->registerHandshake([&]()
350 {
351 return Handshake();
352 });
353 registerConnection(serialConnection);
354
355 return true;
356 }
357
updateProperties()358 bool PegasusUPB::updateProperties()
359 {
360 INDI::DefaultDevice::updateProperties();
361
362 if (isConnected())
363 {
364 // Setup Parameters
365 setupParams();
366
367 // Main Control
368 defineProperty(&PowerCycleAllSP);
369 defineProperty(&PowerSensorsNP);
370 defineProperty(&PowerConsumptionNP);
371 defineProperty(&RebootSP);
372
373 // Power
374 defineProperty(&PowerControlSP);
375 defineProperty(&PowerControlsLabelsTP);
376 defineProperty(&PowerCurrentNP);
377 defineProperty(&PowerOnBootSP);
378 OverCurrentLP.nlp = (version == UPB_V1) ? 4 : 7;
379 defineProperty(&OverCurrentLP);
380 if (version == UPB_V1)
381 defineProperty(&PowerLEDSP);
382 if (version == UPB_V2)
383 defineProperty(&AdjustableOutputNP);
384
385 // Dew
386 if (version == UPB_V1)
387 defineProperty(&AutoDewSP);
388 else
389 defineProperty(&AutoDewV2SP);
390
391 DewControlsLabelsTP.ntp = (version == UPB_V1) ? 2 : 3;
392 defineProperty(&DewControlsLabelsTP);
393
394 if (version == UPB_V2)
395 defineProperty(&AutoDewAggNP);
396
397 DewPWMNP.nnp = (version == UPB_V1) ? 2 : 3;
398 defineProperty(&DewPWMNP);
399
400 DewCurrentDrawNP.nnp = (version == UPB_V1) ? 2 : 3;
401 defineProperty(&DewCurrentDrawNP);
402
403 // USB
404 defineProperty(&USBControlSP);
405 if (version == UPB_V2)
406 defineProperty(&USBControlV2SP);
407 if (version == UPB_V1)
408 defineProperty(&USBStatusLP);
409 defineProperty(&USBControlsLabelsTP);
410
411 // Focuser
412 FI::updateProperties();
413 defineProperty(&FocuserSettingsNP);
414
415 WI::updateProperties();
416
417 // Firmware
418 defineProperty(&FirmwareTP);
419
420 setupComplete = true;
421 }
422 else
423 {
424 // Main Control
425 deleteProperty(PowerCycleAllSP.name);
426 deleteProperty(PowerSensorsNP.name);
427 deleteProperty(PowerConsumptionNP.name);
428 deleteProperty(RebootSP.name);
429
430 // Power
431 deleteProperty(PowerControlSP.name);
432 deleteProperty(PowerControlsLabelsTP.name);
433 deleteProperty(PowerCurrentNP.name);
434 deleteProperty(PowerOnBootSP.name);
435 deleteProperty(OverCurrentLP.name);
436 if (version == UPB_V1)
437 deleteProperty(PowerLEDSP.name);
438 if (version == UPB_V2)
439 deleteProperty(AdjustableOutputNP.name);
440
441 // Dew
442 if (version == UPB_V1)
443 deleteProperty(AutoDewSP.name);
444 else
445 {
446 deleteProperty(AutoDewV2SP.name);
447 deleteProperty(DewControlsLabelsTP.name);
448 deleteProperty(AutoDewAggNP.name);
449 }
450
451 deleteProperty(DewPWMNP.name);
452 deleteProperty(DewCurrentDrawNP.name);
453
454 // USB
455 deleteProperty(USBControlSP.name);
456 if (version == UPB_V2)
457 deleteProperty(USBControlV2SP.name);
458 if (version == UPB_V1)
459 deleteProperty(USBStatusLP.name);
460 deleteProperty(USBControlsLabelsTP.name);
461
462 // Focuser
463 FI::updateProperties();
464 deleteProperty(FocuserSettingsNP.name);
465
466 WI::updateProperties();
467
468 deleteProperty(FirmwareTP.name);
469
470 setupComplete = false;
471 }
472
473 return true;
474 }
475
getDefaultName()476 const char * PegasusUPB::getDefaultName()
477 {
478 return "Pegasus UPB";
479 }
480
481 //////////////////////////////////////////////////////////////////////
482 ///
483 //////////////////////////////////////////////////////////////////////
Handshake()484 bool PegasusUPB::Handshake()
485 {
486 char response[PEGASUS_LEN] = {0};
487 int nbytes_read = 0;
488 PortFD = serialConnection->getPortFD();
489
490 LOG_DEBUG("CMD <P#>");
491
492 if (isSimulation())
493 {
494 snprintf(response, PEGASUS_LEN, "UPB2_OK");
495 nbytes_read = 8;
496 }
497 else
498 {
499 int tty_rc = 0, nbytes_written = 0;
500 char command[PEGASUS_LEN] = {0};
501 tcflush(PortFD, TCIOFLUSH);
502 strncpy(command, "P#\n", PEGASUS_LEN);
503 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
504 {
505 char errorMessage[MAXRBUF];
506 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
507 LOGF_ERROR("Serial write error: %s", errorMessage);
508 return false;
509 }
510
511 // Try first with stopChar as the stop character
512 if ( (tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read)) != TTY_OK)
513 {
514 // Try 0xA as the stop character
515 if (tty_rc == TTY_OVERFLOW || tty_rc == TTY_TIME_OUT)
516 {
517 tcflush(PortFD, TCIOFLUSH);
518 tty_write_string(PortFD, command, &nbytes_written);
519 stopChar = 0xA;
520 tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read);
521 }
522
523 if (tty_rc != TTY_OK)
524 {
525 char errorMessage[MAXRBUF];
526 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
527 LOGF_ERROR("Serial read error: %s", errorMessage);
528 return false;
529 }
530 }
531
532 cleanupResponse(response);
533 tcflush(PortFD, TCIOFLUSH);
534 }
535
536
537 LOGF_DEBUG("RES <%s>", response);
538
539 setupComplete = false;
540
541 version = strstr(response, "UPB2_OK") ? UPB_V2 : UPB_V1;
542
543 return true;
544 }
545
546 //////////////////////////////////////////////////////////////////////
547 ///
548 //////////////////////////////////////////////////////////////////////
ISNewSwitch(const char * dev,const char * name,ISState * states,char * names[],int n)549 bool PegasusUPB::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
550 {
551 if (dev && !strcmp(dev, getDeviceName()))
552 {
553 // Cycle all power on or off
554 if (!strcmp(name, PowerCycleAllSP.name))
555 {
556 IUUpdateSwitch(&PowerCycleAllSP, states, names, n);
557
558 PowerCycleAllSP.s = IPS_ALERT;
559 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
560 snprintf(cmd, PEGASUS_LEN, "PZ:%d", IUFindOnSwitchIndex(&PowerCycleAllSP));
561 if (sendCommand(cmd, res))
562 {
563 PowerCycleAllSP.s = !strcmp(cmd, res) ? IPS_OK : IPS_ALERT;
564 }
565
566 IUResetSwitch(&PowerCycleAllSP);
567 IDSetSwitch(&PowerCycleAllSP, nullptr);
568 return true;
569 }
570
571 // Reboot
572 if (!strcmp(name, RebootSP.name))
573 {
574 RebootSP.s = reboot() ? IPS_OK : IPS_ALERT;
575 IDSetSwitch(&RebootSP, nullptr);
576 LOG_INFO("Rebooting device...");
577 return true;
578 }
579
580 // Control Power per port
581 if (!strcmp(name, PowerControlSP.name))
582 {
583 bool failed = false;
584 for (int i = 0; i < n; i++)
585 {
586 if (!strcmp(names[i], PowerControlS[i].name) && states[i] != PowerControlS[i].s)
587 {
588 if (setPowerEnabled(i + 1, states[i] == ISS_ON) == false)
589 {
590 failed = true;
591 break;
592 }
593 }
594 }
595
596 if (failed)
597 PowerControlSP.s = IPS_ALERT;
598 else
599 {
600 PowerControlSP.s = IPS_OK;
601 IUUpdateSwitch(&PowerControlSP, states, names, n);
602 }
603
604 IDSetSwitch(&PowerControlSP, nullptr);
605 return true;
606 }
607
608 // Power on boot
609 if (!strcmp(name, PowerOnBootSP.name))
610 {
611 IUUpdateSwitch(&PowerOnBootSP, states, names, n);
612 PowerOnBootSP.s = setPowerOnBoot() ? IPS_OK : IPS_ALERT;
613 IDSetSwitch(&PowerOnBootSP, nullptr);
614 saveConfig(true, PowerOnBootSP.name);
615 return true;
616 }
617
618 // Auto Dew v1.
619 if ((!strcmp(name, AutoDewSP.name)) && (version == UPB_V1))
620 {
621 int prevIndex = IUFindOnSwitchIndex(&AutoDewSP);
622 IUUpdateSwitch(&AutoDewSP, states, names, n);
623 if (setAutoDewEnabled(AutoDewS[INDI_ENABLED].s == ISS_ON))
624 {
625 AutoDewSP.s = IPS_OK;
626 }
627 else
628 {
629 IUResetSwitch(&AutoDewSP);
630 AutoDewS[prevIndex].s = ISS_ON;
631 AutoDewSP.s = IPS_ALERT;
632 }
633
634 IDSetSwitch(&AutoDewSP, nullptr);
635 return true;
636 }
637
638 // Auto Dew v2.
639 if ((!strcmp(name, AutoDewV2SP.name)) && (version == UPB_V2))
640 {
641 ISState Dew1 = AutoDewV2S[DEW_PWM_A].s;
642 ISState Dew2 = AutoDewV2S[DEW_PWM_B].s;
643 ISState Dew3 = AutoDewV2S[DEW_PWM_C].s;
644 IUUpdateSwitch(&AutoDewV2SP, states, names, n);
645 if (toggleAutoDewV2())
646 {
647 Dew1 = AutoDewV2S[DEW_PWM_A].s;
648 Dew2 = AutoDewV2S[DEW_PWM_B].s;
649 Dew3 = AutoDewV2S[DEW_PWM_C].s;
650 if (Dew1 == ISS_OFF && Dew2 == ISS_OFF && Dew3 == ISS_OFF)
651 AutoDewV2SP.s = IPS_IDLE;
652 else
653 AutoDewV2SP.s = IPS_OK;
654 }
655 else
656 {
657 IUResetSwitch(&AutoDewV2SP);
658 AutoDewV2S[DEW_PWM_A].s = Dew1;
659 AutoDewV2S[DEW_PWM_B].s = Dew2;
660 AutoDewV2S[DEW_PWM_C].s = Dew3;
661 AutoDewV2SP.s = IPS_ALERT;
662 }
663
664 IDSetSwitch(&AutoDewV2SP, nullptr);
665 return true;
666 }
667
668 // USB Hub Control v1
669 if (!strcmp(name, USBControlSP.name))
670 {
671 int prevIndex = IUFindOnSwitchIndex(&USBControlSP);
672 IUUpdateSwitch(&USBControlSP, states, names, n);
673 if (setUSBHubEnabled(USBControlS[0].s == ISS_ON))
674 {
675 USBControlSP.s = IPS_OK;
676 }
677 else
678 {
679 IUResetSwitch(&USBControlSP);
680 USBControlS[prevIndex].s = ISS_ON;
681 USBControlSP.s = IPS_ALERT;
682 }
683
684 IDSetSwitch(&USBControlSP, nullptr);
685 return true;
686 }
687
688 // USB Hub Control v2
689 if (!strcmp(name, USBControlV2SP.name))
690 {
691 bool rc[6] = {true};
692 ISState ports[6] = {ISS_ON};
693
694 for (int i = 0; i < USBControlV2SP.nsp; i++)
695 ports[i] = USBControlV2S[i].s;
696
697 IUUpdateSwitch(&USBControlV2SP, states, names, n);
698 for (int i = 0; i < USBControlV2SP.nsp; i++)
699 {
700 if (ports[i] != USBControlV2S[i].s)
701 rc[i] = setUSBPortEnabled(i, USBControlV2S[i].s == ISS_ON);
702 }
703
704 // All is OK
705 if (rc[0] && rc[1] && rc[2] && rc[3] && rc[4] && rc[5])
706 {
707 USBControlSP.s = IPS_OK;
708 }
709 else
710 {
711 IUResetSwitch(&USBControlV2SP);
712 for (int i = 0; i < USBControlV2SP.nsp; i++)
713 USBControlV2S[i].s = ports[i];
714 USBControlV2SP.s = IPS_ALERT;
715 }
716
717 IDSetSwitch(&USBControlSP, nullptr);
718 return true;
719 }
720
721 // Focuser backlash
722 // if (!strcmp(name, FocusBacklashSP.name))
723 // {
724 // int prevIndex = IUFindOnSwitchIndex(&FocusBacklashSP);
725 // IUUpdateSwitch(&FocusBacklashSP, states, names, n);
726 // if (setFocuserBacklashEnabled(FocusBacklashS[0].s == ISS_ON))
727 // {
728 // FocusBacklashSP.s = IPS_OK;
729 // }
730 // else
731 // {
732 // IUResetSwitch(&FocusBacklashSP);
733 // FocusBacklashS[prevIndex].s = ISS_ON;
734 // FocusBacklashSP.s = IPS_ALERT;
735 // }
736
737 // IDSetSwitch(&FocusBacklashSP, nullptr);
738 // return true;
739 // }
740
741 // Power LED
742 if (!strcmp(name, PowerLEDSP.name) && (version == UPB_V1))
743 {
744 int prevIndex = IUFindOnSwitchIndex(&PowerLEDSP);
745 IUUpdateSwitch(&PowerLEDSP, states, names, n);
746 if (setPowerLEDEnabled(PowerLEDS[0].s == ISS_ON))
747 {
748 PowerLEDSP.s = IPS_OK;
749 }
750 else
751 {
752 IUResetSwitch(&PowerLEDSP);
753 PowerLEDS[prevIndex].s = ISS_ON;
754 PowerLEDSP.s = IPS_ALERT;
755 }
756
757 IDSetSwitch(&PowerLEDSP, nullptr);
758 return true;
759 }
760
761 if (strstr(name, "FOCUS"))
762 return FI::processSwitch(dev, name, states, names, n);
763 }
764
765 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
766 }
767
768 //////////////////////////////////////////////////////////////////////
769 ///
770 //////////////////////////////////////////////////////////////////////
ISNewNumber(const char * dev,const char * name,double values[],char * names[],int n)771 bool PegasusUPB::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
772 {
773 if (dev && !strcmp(dev, getDeviceName()))
774 {
775 // Adjustable output
776 if (!strcmp(name, AdjustableOutputNP.name))
777 {
778 if (setAdjustableOutput(static_cast<uint8_t>(values[0])))
779 {
780 IUUpdateNumber(&AdjustableOutputNP, values, names, n);
781 AdjustableOutputNP.s = IPS_OK;
782 }
783 else
784 AdjustableOutputNP.s = IPS_ALERT;
785
786 IDSetNumber(&AdjustableOutputNP, nullptr);
787 return true;
788 }
789
790 // Dew PWM
791 if (!strcmp(name, DewPWMNP.name))
792 {
793 bool rc1 = false, rc2 = false, rc3 = false;
794 for (int i = 0; i < n; i++)
795 {
796 if (!strcmp(names[i], DewPWMN[DEW_PWM_A].name))
797 rc1 = setDewPWM(5, static_cast<uint8_t>(values[i] / 100.0 * 255.0));
798 else if (!strcmp(names[i], DewPWMN[DEW_PWM_B].name))
799 rc2 = setDewPWM(6, static_cast<uint8_t>(values[i] / 100.0 * 255.0));
800 else if (!strcmp(names[i], DewPWMN[DEW_PWM_C].name))
801 rc3 = setDewPWM(7, static_cast<uint8_t>(values[i] / 100.0 * 255.0));
802 }
803
804 DewPWMNP.s = (rc1 && rc2 && rc3) ? IPS_OK : IPS_ALERT;
805 if (DewPWMNP.s == IPS_OK)
806 IUUpdateNumber(&DewPWMNP, values, names, n);
807 IDSetNumber(&DewPWMNP, nullptr);
808 return true;
809 }
810
811 // Auto Dew Aggressiveness
812 if (!strcmp(name, AutoDewAggNP.name))
813 {
814 if (setAutoDewAgg(values[0]))
815 {
816 AutoDewAggN[0].value = values[0];
817 AutoDewAggNP.s = IPS_OK;
818 }
819 else
820 {
821 AutoDewAggNP.s = IPS_ALERT;
822 }
823
824 IDSetNumber(&AutoDewAggNP, nullptr);
825 return true;
826 }
827
828 // Focuser Settings
829 if (!strcmp(name, FocuserSettingsNP.name))
830 {
831 if (setFocuserMaxSpeed(values[0]))
832 {
833 FocuserSettingsN[0].value = values[0];
834 FocuserSettingsNP.s = IPS_OK;
835 }
836 else
837 {
838 FocuserSettingsNP.s = IPS_ALERT;
839 }
840
841 IDSetNumber(&FocuserSettingsNP, nullptr);
842 return true;
843 }
844
845 if (strstr(name, "FOCUS_"))
846 return FI::processNumber(dev, name, values, names, n);
847
848 if (strstr(name, "WEATHER_"))
849 return WI::processNumber(dev, name, values, names, n);
850 }
851 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
852 }
853
854 //////////////////////////////////////////////////////////////////////
855 ///
856 //////////////////////////////////////////////////////////////////////
ISNewText(const char * dev,const char * name,char * texts[],char * names[],int n)857 bool PegasusUPB::ISNewText(const char * dev, const char * name, char * texts[], char * names[], int n)
858 {
859 if (dev && !strcmp(dev, getDeviceName()))
860 {
861 // Power Labels
862 if (!strcmp(name, PowerControlsLabelsTP.name))
863 {
864 IUUpdateText(&PowerControlsLabelsTP, texts, names, n);
865 PowerControlsLabelsTP.s = IPS_OK;
866 LOG_INFO("Power port labels saved. Driver must be restarted for the labels to take effect.");
867 saveConfig();
868 IDSetText(&PowerControlsLabelsTP, nullptr);
869 return true;
870 }
871 // Dew Labels
872 if (!strcmp(name, DewControlsLabelsTP.name))
873 {
874 IUUpdateText(&DewControlsLabelsTP, texts, names, n);
875 DewControlsLabelsTP.s = IPS_OK;
876 LOG_INFO("Dew labels saved. Driver must be restarted for the labels to take effect.");
877 saveConfig();
878 IDSetText(&DewControlsLabelsTP, nullptr);
879 return true;
880 }
881 // USB Labels
882 if (!strcmp(name, USBControlsLabelsTP.name))
883 {
884 IUUpdateText(&USBControlsLabelsTP, texts, names, n);
885 USBControlsLabelsTP.s = IPS_OK;
886 LOG_INFO("USB labels saved. Driver must be restarted for the labels to take effect.");
887 saveConfig();
888 IDSetText(&USBControlsLabelsTP, nullptr);
889 return true;
890 }
891 }
892
893 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
894 }
895
896 //////////////////////////////////////////////////////////////////////
897 ///
898 //////////////////////////////////////////////////////////////////////
sendCommand(const char * cmd,char * res)899 bool PegasusUPB::sendCommand(const char * cmd, char * res)
900 {
901 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
902 LOGF_DEBUG("CMD <%s>", cmd);
903
904 if (isSimulation())
905 {
906 if (!strcmp(cmd, "PS"))
907 {
908 strncpy(res, "PS:1111:12", PEGASUS_LEN);
909 }
910 else if (!strcmp(cmd, "PA"))
911 {
912 strncpy(res, "UPB2:12.0:0.9:10:24.8:37:9.1:1111:111111:153:153:0:0:0:0:0:70:0:0:0000000:0", PEGASUS_LEN);
913 }
914 else if (!strcmp(cmd, "PC"))
915 {
916 strncpy(res, "0.40:0.00:0.03:26969", PEGASUS_LEN);
917 }
918 else if (!strcmp(cmd, "SA"))
919 {
920 strncpy(res, "3000:0:0:10", PEGASUS_LEN);
921 }
922 else if (!strcmp(cmd, "SS"))
923 {
924 strncpy(res, "999", PEGASUS_LEN);
925 }
926 else if (!strcmp(cmd, "PD"))
927 {
928 strncpy(res, "210", PEGASUS_LEN);
929 }
930 else if (!strcmp(cmd, "PV"))
931 {
932 strncpy(res, "Sim v1.0", PEGASUS_LEN);
933 }
934 else if (res)
935 {
936 strncpy(res, cmd, PEGASUS_LEN);
937 }
938
939 return true;
940 }
941
942 for (int i = 0; i < 2; i++)
943 {
944 char command[PEGASUS_LEN] = {0};
945 tcflush(PortFD, TCIOFLUSH);
946 snprintf(command, PEGASUS_LEN, "%s\n", cmd);
947 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
948 continue;
949
950 if (!res)
951 {
952 tcflush(PortFD, TCIOFLUSH);
953 return true;
954 }
955
956 if ( (tty_rc = tty_nread_section(PortFD, res, PEGASUS_LEN, stopChar, PEGASUS_TIMEOUT, &nbytes_read)) != TTY_OK
957 || nbytes_read == 1)
958 continue;
959
960 tcflush(PortFD, TCIOFLUSH);
961
962 cleanupResponse(res);
963 LOGF_DEBUG("RES <%s>", res);
964 return true;
965 }
966
967 if (tty_rc != TTY_OK)
968 {
969 char errorMessage[MAXRBUF];
970 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
971 LOGF_ERROR("Serial error: %s", errorMessage);
972 }
973
974 return false;
975 }
976
977 //////////////////////////////////////////////////////////////////////
978 ///
979 //////////////////////////////////////////////////////////////////////
MoveAbsFocuser(uint32_t targetTicks)980 IPState PegasusUPB::MoveAbsFocuser(uint32_t targetTicks)
981 {
982 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
983 snprintf(cmd, PEGASUS_LEN, "SM:%u", targetTicks);
984 if (sendCommand(cmd, res))
985 {
986 return (!strcmp(res, cmd) ? IPS_BUSY : IPS_ALERT);
987 }
988
989 return IPS_ALERT;
990 }
991
992 //////////////////////////////////////////////////////////////////////
993 ///
994 //////////////////////////////////////////////////////////////////////
MoveRelFocuser(FocusDirection dir,uint32_t ticks)995 IPState PegasusUPB::MoveRelFocuser(FocusDirection dir, uint32_t ticks)
996 {
997 return MoveAbsFocuser(dir == FOCUS_INWARD ? FocusAbsPosN[0].value - ticks : FocusAbsPosN[0].value + ticks);
998 }
999
1000 //////////////////////////////////////////////////////////////////////
1001 ///
1002 //////////////////////////////////////////////////////////////////////
AbortFocuser()1003 bool PegasusUPB::AbortFocuser()
1004 {
1005 char res[PEGASUS_LEN] = {0};
1006 if (sendCommand("SH", res))
1007 {
1008 return (!strcmp(res, "SH"));
1009 }
1010
1011 return false;
1012 }
1013
1014 //////////////////////////////////////////////////////////////////////
1015 ///
1016 //////////////////////////////////////////////////////////////////////
ReverseFocuser(bool enabled)1017 bool PegasusUPB::ReverseFocuser(bool enabled)
1018 {
1019 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1020 snprintf(cmd, PEGASUS_LEN, "SR:%d", enabled ? 1 : 0);
1021 if (sendCommand(cmd, res))
1022 {
1023 return (!strcmp(res, cmd));
1024 }
1025
1026 return false;
1027 }
1028
1029 //////////////////////////////////////////////////////////////////////
1030 ///
1031 //////////////////////////////////////////////////////////////////////
SyncFocuser(uint32_t ticks)1032 bool PegasusUPB::SyncFocuser(uint32_t ticks)
1033 {
1034 char cmd[PEGASUS_LEN] = {0};
1035 snprintf(cmd, PEGASUS_LEN, "SC:%u", ticks);
1036 return sendCommand(cmd, nullptr);
1037 }
1038
1039 //////////////////////////////////////////////////////////////////////
1040 ///
1041 //////////////////////////////////////////////////////////////////////
SetFocuserBacklash(int32_t steps)1042 bool PegasusUPB::SetFocuserBacklash(int32_t steps)
1043 {
1044 char cmd[PEGASUS_LEN] = {0};
1045 snprintf(cmd, PEGASUS_LEN, "SB:%d", steps);
1046 return sendCommand(cmd, nullptr);
1047 }
1048
1049 //////////////////////////////////////////////////////////////////////
1050 ///
1051 //////////////////////////////////////////////////////////////////////
setFocuserMaxSpeed(uint16_t maxSpeed)1052 bool PegasusUPB::setFocuserMaxSpeed(uint16_t maxSpeed)
1053 {
1054 char cmd[PEGASUS_LEN] = {0};
1055 snprintf(cmd, PEGASUS_LEN, "SS:%d", maxSpeed);
1056 return sendCommand(cmd, nullptr);
1057 }
1058
1059 //////////////////////////////////////////////////////////////////////
1060 ///
1061 //////////////////////////////////////////////////////////////////////
SetFocuserBacklashEnabled(bool enabled)1062 bool PegasusUPB::SetFocuserBacklashEnabled(bool enabled)
1063 {
1064 char cmd[PEGASUS_LEN] = {0};
1065 snprintf(cmd, PEGASUS_LEN, "SB:%d", enabled ? 1 : 0);
1066 return sendCommand(cmd, nullptr);
1067 }
1068
1069 //////////////////////////////////////////////////////////////////////
1070 ///
1071 //////////////////////////////////////////////////////////////////////
setPowerEnabled(uint8_t port,bool enabled)1072 bool PegasusUPB::setPowerEnabled(uint8_t port, bool enabled)
1073 {
1074 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1075 snprintf(cmd, PEGASUS_LEN, "P%d:%d", port, enabled ? 1 : 0);
1076 if (sendCommand(cmd, res))
1077 {
1078 return (!strcmp(res, cmd));
1079 }
1080
1081 return false;
1082 }
1083
1084 //////////////////////////////////////////////////////////////////////
1085 ///
1086 //////////////////////////////////////////////////////////////////////
setPowerLEDEnabled(bool enabled)1087 bool PegasusUPB::setPowerLEDEnabled(bool enabled)
1088 {
1089 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1090 snprintf(cmd, PEGASUS_LEN, "PL:%d", enabled ? 1 : 0);
1091 if (sendCommand(cmd, res))
1092 {
1093 return (!strcmp(res, cmd));
1094 }
1095
1096 return false;
1097 }
1098
1099 //////////////////////////////////////////////////////////////////////
1100 ///
1101 //////////////////////////////////////////////////////////////////////
setAutoDewEnabled(bool enabled)1102 bool PegasusUPB::setAutoDewEnabled(bool enabled)
1103 {
1104 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1105 snprintf(cmd, PEGASUS_LEN, "PD:%d", enabled ? 1 : 0);
1106 if (sendCommand(cmd, res))
1107 {
1108 return (!strcmp(res, cmd));
1109 }
1110
1111 return false;
1112 }
1113
1114 //////////////////////////////////////////////////////////////////////
1115 ///
1116 //////////////////////////////////////////////////////////////////////
setAutoDewAgg(uint8_t value)1117 bool PegasusUPB::setAutoDewAgg(uint8_t value)
1118 {
1119 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
1120 snprintf(cmd, PEGASUS_LEN, "PD:%03d", value);
1121 snprintf(expected, PEGASUS_LEN, "PD:%d", value);
1122 if (sendCommand(cmd, res))
1123 {
1124 return (!strcmp(res, expected));
1125 }
1126
1127 return false;
1128 }
1129 //////////////////////////////////////////////////////////////////////
1130 ///
1131 //////////////////////////////////////////////////////////////////////
setAdjustableOutput(uint8_t voltage)1132 bool PegasusUPB::setAdjustableOutput(uint8_t voltage)
1133 {
1134 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1135 snprintf(cmd, PEGASUS_LEN, "P8:%d", voltage);
1136 if (sendCommand(cmd, res))
1137 {
1138 return (!strcmp(res, cmd));
1139 }
1140
1141 return false;
1142 }
1143
1144 //////////////////////////////////////////////////////////////////////
1145 ///
1146 //////////////////////////////////////////////////////////////////////
setPowerOnBoot()1147 bool PegasusUPB::setPowerOnBoot()
1148 {
1149 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1150 snprintf(cmd, PEGASUS_LEN, "PE:%d%d%d%d", PowerOnBootS[0].s == ISS_ON ? 1 : 0,
1151 PowerOnBootS[1].s == ISS_ON ? 1 : 0,
1152 PowerOnBootS[2].s == ISS_ON ? 1 : 0,
1153 PowerOnBootS[3].s == ISS_ON ? 1 : 0);
1154 if (sendCommand(cmd, res))
1155 {
1156 return (!strcmp(res, "PE:1"));
1157 }
1158
1159 return false;
1160 }
1161
1162 //////////////////////////////////////////////////////////////////////
1163 ///
1164 //////////////////////////////////////////////////////////////////////
getPowerOnBoot()1165 bool PegasusUPB::getPowerOnBoot()
1166 {
1167 char res[PEGASUS_LEN] = {0};
1168 if (sendCommand("PS", res))
1169 {
1170 std::vector<std::string> result = split(res, ":");
1171 if (result.size() != 3)
1172 {
1173 LOGF_WARN("Received wrong number (%i) of power on boot data (%s). Retrying...", result.size(), res);
1174 return false;
1175 }
1176
1177 const char *status = result[1].c_str();
1178 PowerOnBootS[0].s = (status[0] == '1') ? ISS_ON : ISS_OFF;
1179 PowerOnBootS[1].s = (status[1] == '1') ? ISS_ON : ISS_OFF;
1180 PowerOnBootS[2].s = (status[2] == '1') ? ISS_ON : ISS_OFF;
1181 PowerOnBootS[3].s = (status[3] == '1') ? ISS_ON : ISS_OFF;
1182
1183 AdjustableOutputN[0].value = std::stod(result[2]);
1184 AdjustableOutputNP.s = IPS_OK;
1185
1186 return true;
1187 }
1188
1189 return false;
1190 }
1191
1192 //////////////////////////////////////////////////////////////////////
1193 ///
1194 //////////////////////////////////////////////////////////////////////
setDewPWM(uint8_t id,uint8_t value)1195 bool PegasusUPB::setDewPWM(uint8_t id, uint8_t value)
1196 {
1197 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
1198 snprintf(cmd, PEGASUS_LEN, "P%d:%03d", id, value);
1199 snprintf(expected, PEGASUS_LEN, "P%d:%d", id, value);
1200 if (sendCommand(cmd, res))
1201 {
1202 return (!strcmp(res, expected));
1203 }
1204
1205 return false;
1206 }
1207
1208 //////////////////////////////////////////////////////////////////////
1209 ///
1210 //////////////////////////////////////////////////////////////////////
setUSBHubEnabled(bool enabled)1211 bool PegasusUPB::setUSBHubEnabled(bool enabled)
1212 {
1213 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1214 snprintf(cmd, PEGASUS_LEN, "PU:%d", enabled ? 1 : 0);
1215 snprintf(expected, PEGASUS_LEN, "PU:%d", enabled ? 0 : 1);
1216 if (sendCommand(cmd, res))
1217 {
1218 return (!strcmp(res, expected));
1219 }
1220
1221 return false;
1222 }
1223
1224 //////////////////////////////////////////////////////////////////////
1225 ///
1226 //////////////////////////////////////////////////////////////////////
setUSBPortEnabled(uint8_t port,bool enabled)1227 bool PegasusUPB::setUSBPortEnabled(uint8_t port, bool enabled)
1228 {
1229 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1230 snprintf(cmd, PEGASUS_LEN, "U%d:%d", port + 1, enabled ? 1 : 0);
1231 snprintf(expected, PEGASUS_LEN, "U%d:%d", port + 1, enabled ? 1 : 0);
1232 if (sendCommand(cmd, res))
1233 {
1234 return (!strcmp(res, expected));
1235 }
1236
1237 return false;
1238 }
1239
1240 //////////////////////////////////////////////////////////////////////
1241 ///
1242 //////////////////////////////////////////////////////////////////////
toggleAutoDewV2()1243 bool PegasusUPB::toggleAutoDewV2()
1244 {
1245 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1246
1247 uint8_t value = 0;
1248
1249 if (IUFindOnSwitchIndex(&AutoDewV2SP) == -1)
1250 value = 0;
1251 else if (AutoDewV2S[DEW_PWM_A].s == ISS_ON && AutoDewV2S[DEW_PWM_B].s == ISS_ON && AutoDewV2S[DEW_PWM_C].s == ISS_ON)
1252 value = 1;
1253 else if (AutoDewV2S[DEW_PWM_A].s == ISS_ON && AutoDewV2S[DEW_PWM_B].s == ISS_ON)
1254 value = 5;
1255 else if (AutoDewV2S[DEW_PWM_A].s == ISS_ON && AutoDewV2S[DEW_PWM_C].s == ISS_ON)
1256 value = 6;
1257 else if (AutoDewV2S[DEW_PWM_B].s == ISS_ON && AutoDewV2S[DEW_PWM_C].s == ISS_ON)
1258 value = 7;
1259 else if (AutoDewV2S[DEW_PWM_A].s == ISS_ON)
1260 value = 2;
1261 else if (AutoDewV2S[DEW_PWM_B].s == ISS_ON)
1262 value = 3;
1263 else if (AutoDewV2S[DEW_PWM_C].s == ISS_ON)
1264 value = 4;
1265
1266 snprintf(cmd, PEGASUS_LEN, "PD:%d", value);
1267 snprintf(expected, PEGASUS_LEN, "PD:%d", value);
1268 if (sendCommand(cmd, res))
1269 {
1270 return (!strcmp(res, expected));
1271 }
1272
1273 return false;
1274 }
1275
1276 //////////////////////////////////////////////////////////////////////
1277 ///
1278 //////////////////////////////////////////////////////////////////////
saveConfigItems(FILE * fp)1279 bool PegasusUPB::saveConfigItems(FILE * fp)
1280 {
1281 // Save CCD Config
1282 INDI::DefaultDevice::saveConfigItems(fp);
1283 FI::saveConfigItems(fp);
1284 WI::saveConfigItems(fp);
1285
1286 IUSaveConfigSwitch(fp, &PowerLEDSP);
1287 IUSaveConfigSwitch(fp, &AutoDewSP);
1288 if (version == UPB_V2)
1289 IUSaveConfigNumber(fp, &AutoDewAggNP);
1290 IUSaveConfigNumber(fp, &FocuserSettingsNP);
1291 IUSaveConfigText(fp, &PowerControlsLabelsTP);
1292 IUSaveConfigText(fp, &DewControlsLabelsTP);
1293 IUSaveConfigText(fp, &USBControlsLabelsTP);
1294 return true;
1295 }
1296
1297 //////////////////////////////////////////////////////////////////////
1298 ///
1299 //////////////////////////////////////////////////////////////////////
TimerHit()1300 void PegasusUPB::TimerHit()
1301 {
1302 if (!isConnected() || setupComplete == false)
1303 {
1304 SetTimer(getCurrentPollingPeriod());
1305 return;
1306 }
1307
1308 if (getSensorData())
1309 {
1310 getPowerData();
1311 getStepperData();
1312
1313 if (version == UPB_V2)
1314 getDewAggData();
1315 }
1316
1317 SetTimer(getCurrentPollingPeriod());
1318 }
1319
1320 //////////////////////////////////////////////////////////////////////
1321 ///
1322 //////////////////////////////////////////////////////////////////////
sendFirmware()1323 bool PegasusUPB::sendFirmware()
1324 {
1325 char res[PEGASUS_LEN] = {0};
1326 if (sendCommand("PV", res))
1327 {
1328 LOGF_INFO("Detected firmware %s", res);
1329 IUSaveText(&FirmwareT[FIRMWARE_VERSION], res);
1330 IDSetText(&FirmwareTP, nullptr);
1331 return true;
1332 }
1333
1334 return false;
1335 }
1336
1337 //////////////////////////////////////////////////////////////////////
1338 ///
1339 //////////////////////////////////////////////////////////////////////
sensorUpdated(const std::vector<std::string> & result,uint8_t start,uint8_t end)1340 bool PegasusUPB::sensorUpdated(const std::vector<std::string> &result, uint8_t start, uint8_t end)
1341 {
1342 for (uint8_t index = start; index <= end; index++)
1343 if (result[index] != lastSensorData[index])
1344 return true;
1345
1346 return false;
1347 }
1348
1349 //////////////////////////////////////////////////////////////////////
1350 ///
1351 //////////////////////////////////////////////////////////////////////
getSensorData()1352 bool PegasusUPB::getSensorData()
1353 {
1354 char res[PEGASUS_LEN] = {0};
1355 if (sendCommand("PA", res))
1356 {
1357 std::vector<std::string> result = split(res, ":");
1358 if ( (version == UPB_V1 && result.size() != 19) ||
1359 (version == UPB_V2 && result.size() != 21))
1360 {
1361 LOGF_WARN("Received wrong number (%i) of detailed sensor data (%s). Retrying...", result.size(), res);
1362 return false;
1363 }
1364
1365 if (result == lastSensorData)
1366 return true;
1367
1368 // Power Sensors
1369 PowerSensorsN[SENSOR_VOLTAGE].value = std::stod(result[1]);
1370 PowerSensorsN[SENSOR_CURRENT].value = std::stod(result[2]);
1371 PowerSensorsN[SENSOR_POWER].value = std::stod(result[3]);
1372 PowerSensorsNP.s = IPS_OK;
1373 //if (lastSensorData[0] != result[0] || lastSensorData[1] != result[1] || lastSensorData[2] != result[2])
1374 if (sensorUpdated(result, 0, 2))
1375 IDSetNumber(&PowerSensorsNP, nullptr);
1376
1377 // Environment Sensors
1378 setParameterValue("WEATHER_TEMPERATURE", std::stod(result[4]));
1379 setParameterValue("WEATHER_HUMIDITY", std::stod(result[5]));
1380 setParameterValue("WEATHER_DEWPOINT", std::stod(result[6]));
1381 //if (lastSensorData[4] != result[4] || lastSensorData[5] != result[5] || lastSensorData[6] != result[6])
1382 if (sensorUpdated(result, 4, 6))
1383 {
1384 if (WI::syncCriticalParameters())
1385 IDSetLight(&critialParametersLP, nullptr);
1386 ParametersNP.s = IPS_OK;
1387 IDSetNumber(&ParametersNP, nullptr);
1388 }
1389
1390 // Port Status
1391 const char * portStatus = result[7].c_str();
1392 PowerControlS[0].s = (portStatus[0] == '1') ? ISS_ON : ISS_OFF;
1393 PowerControlS[1].s = (portStatus[1] == '1') ? ISS_ON : ISS_OFF;
1394 PowerControlS[2].s = (portStatus[2] == '1') ? ISS_ON : ISS_OFF;
1395 PowerControlS[3].s = (portStatus[3] == '1') ? ISS_ON : ISS_OFF;
1396 //if (lastSensorData[7] != result[7])
1397 if (sensorUpdated(result, 7, 7))
1398 IDSetSwitch(&PowerControlSP, nullptr);
1399
1400 // Hub Status
1401 const char * usb_status = result[8].c_str();
1402 if (version == UPB_V1)
1403 {
1404 USBControlS[0].s = (usb_status[0] == '0') ? ISS_ON : ISS_OFF;
1405 USBControlS[1].s = (usb_status[0] == '0') ? ISS_OFF : ISS_ON;
1406 USBStatusL[0].s = (USBControlS[0].s == ISS_ON) ? IPS_OK : IPS_IDLE;
1407 USBStatusL[1].s = (USBControlS[0].s == ISS_ON) ? IPS_OK : IPS_IDLE;
1408 USBStatusL[2].s = (USBControlS[0].s == ISS_ON) ? IPS_OK : IPS_IDLE;
1409 USBStatusL[3].s = (USBControlS[0].s == ISS_ON) ? IPS_OK : IPS_IDLE;
1410 USBStatusL[4].s = (USBControlS[0].s == ISS_ON) ? IPS_OK : IPS_IDLE;
1411 //if (lastSensorData[8] != result[8])
1412 if (sensorUpdated(result, 8, 8))
1413 {
1414 USBControlSP.s = (IUFindOnSwitchIndex(&USBControlSP) == 0) ? IPS_OK : IPS_IDLE;
1415 IDSetSwitch(&USBControlSP, nullptr);
1416 IDSetLight(&USBStatusLP, nullptr);
1417 }
1418 }
1419 else
1420 {
1421 USBControlV2S[0].s = (usb_status[0] == '1') ? ISS_ON : ISS_OFF;
1422 USBControlV2S[1].s = (usb_status[1] == '1') ? ISS_ON : ISS_OFF;
1423 USBControlV2S[2].s = (usb_status[2] == '1') ? ISS_ON : ISS_OFF;
1424 USBControlV2S[3].s = (usb_status[3] == '1') ? ISS_ON : ISS_OFF;
1425 USBControlV2S[4].s = (usb_status[4] == '1') ? ISS_ON : ISS_OFF;
1426 USBControlV2S[5].s = (usb_status[5] == '1') ? ISS_ON : ISS_OFF;
1427 USBControlV2SP.s = IPS_OK;
1428 //if (lastSensorData[8] != result[8])
1429 if (sensorUpdated(result, 8, 8))
1430 {
1431 IDSetSwitch(&USBControlV2SP, nullptr);
1432 }
1433 }
1434
1435 // From here, we get differences between v1 and v2 readings
1436 int index = 9;
1437 // Dew PWM
1438 DewPWMN[DEW_PWM_A].value = std::stod(result[index]) / 255.0 * 100.0;
1439 DewPWMN[DEW_PWM_B].value = std::stod(result[index + 1]) / 255.0 * 100.0;
1440 if (version == UPB_V2)
1441 DewPWMN[DEW_PWM_C].value = std::stod(result[index + 2]) / 255.0 * 100.0;
1442 // if (lastSensorData[index] != result[index] ||
1443 // lastSensorData[index + 1] != result[index + 1] ||
1444 // (version == UPB_V2 && lastSensorData[index +2] != result[index + 2]))
1445 if (sensorUpdated(result, index, version == UPB_V1 ? index + 1 : index + 2))
1446 IDSetNumber(&DewPWMNP, nullptr);
1447
1448 index = (version == UPB_V1) ? 11 : 12;
1449
1450 const double ampDivision = (version == UPB_V1) ? 400.0 : 300.0;
1451
1452 // Current draw
1453 PowerCurrentN[0].value = std::stod(result[index]) / ampDivision;
1454 PowerCurrentN[1].value = std::stod(result[index + 1]) / ampDivision;
1455 PowerCurrentN[2].value = std::stod(result[index + 2]) / ampDivision;
1456 PowerCurrentN[3].value = std::stod(result[index + 3]) / ampDivision;
1457 // if (lastSensorData[index] != result[index] ||
1458 // lastSensorData[index + 1] != result[index + 1] ||
1459 // lastSensorData[index + 2] != result[index + 2] ||
1460 // lastSensorData[index + 3] != result[index + 3])
1461 if (sensorUpdated(result, index, index + 3))
1462 IDSetNumber(&PowerCurrentNP, nullptr);
1463
1464 index = (version == UPB_V1) ? 15 : 16;
1465
1466 DewCurrentDrawN[DEW_PWM_A].value = std::stod(result[index]) / ampDivision;
1467 DewCurrentDrawN[DEW_PWM_B].value = std::stod(result[index + 1]) / ampDivision;
1468 if (version == UPB_V2)
1469 DewCurrentDrawN[DEW_PWM_C].value = std::stod(result[index + 2]) / (ampDivision * 2);
1470 // if (lastSensorData[index] != result[index] ||
1471 // lastSensorData[index + 1] != result[index + 1] ||
1472 // (version == UPB_V2 && lastSensorData[index + 2] != result[index + 2]))
1473 if (sensorUpdated(result, index, version == UPB_V1 ? index + 1 : index + 2))
1474 IDSetNumber(&DewCurrentDrawNP, nullptr);
1475
1476 index = (version == UPB_V1) ? 17 : 19;
1477
1478 // Over Current
1479 //if (lastSensorData[index] != result[index])
1480 if (sensorUpdated(result, index, index))
1481 {
1482 const char * over_curent = result[index].c_str();
1483 OverCurrentL[0].s = (over_curent[0] == '0') ? IPS_OK : IPS_ALERT;
1484 OverCurrentL[1].s = (over_curent[1] == '0') ? IPS_OK : IPS_ALERT;
1485 OverCurrentL[2].s = (over_curent[2] == '0') ? IPS_OK : IPS_ALERT;
1486 OverCurrentL[3].s = (over_curent[3] == '0') ? IPS_OK : IPS_ALERT;
1487 if (version == UPB_V2)
1488 {
1489 OverCurrentL[4].s = (over_curent[4] == '0') ? IPS_OK : IPS_ALERT;
1490 OverCurrentL[5].s = (over_curent[5] == '0') ? IPS_OK : IPS_ALERT;
1491 OverCurrentL[6].s = (over_curent[6] == '0') ? IPS_OK : IPS_ALERT;
1492 }
1493
1494 IDSetLight(&OverCurrentLP, nullptr);
1495 }
1496
1497 index = (version == UPB_V1) ? 18 : 20;
1498
1499 // Auto Dew
1500 if (version == UPB_V1)
1501 {
1502 //if (lastSensorData[index] != result[index])
1503 if (sensorUpdated(result, index, index))
1504 {
1505 AutoDewS[INDI_ENABLED].s = (std::stoi(result[index]) == 1) ? ISS_ON : ISS_OFF;
1506 AutoDewS[INDI_DISABLED].s = (std::stoi(result[index]) == 1) ? ISS_OFF : ISS_ON;
1507 IDSetSwitch(&AutoDewSP, nullptr);
1508 }
1509 }
1510 else
1511 {
1512 //if (lastSensorData[index] != result[index])
1513 if (sensorUpdated(result, index, index))
1514 {
1515 int value = std::stoi(result[index]);
1516 IUResetSwitch(&AutoDewV2SP);
1517 switch (value)
1518 {
1519 case 1:
1520 AutoDewV2S[DEW_PWM_A].s = AutoDewV2S[DEW_PWM_B].s = AutoDewV2S[DEW_PWM_C].s = ISS_ON;
1521 break;
1522
1523 case 2:
1524 AutoDewV2S[DEW_PWM_A].s = ISS_ON;
1525 break;
1526
1527 case 3:
1528 AutoDewV2S[DEW_PWM_B].s = ISS_ON;
1529 break;
1530
1531 case 4:
1532 AutoDewV2S[DEW_PWM_C].s = ISS_ON;
1533 break;
1534
1535 case 5:
1536 AutoDewV2S[DEW_PWM_A].s = ISS_ON;
1537 AutoDewV2S[DEW_PWM_B].s = ISS_ON;
1538 break;
1539
1540 case 6:
1541 AutoDewV2S[DEW_PWM_A].s = ISS_ON;
1542 AutoDewV2S[DEW_PWM_C].s = ISS_ON;
1543 break;
1544
1545 case 7:
1546 AutoDewV2S[DEW_PWM_B].s = ISS_ON;
1547 AutoDewV2S[DEW_PWM_C].s = ISS_ON;
1548 break;
1549 default:
1550 break;
1551 }
1552 IDSetSwitch(&AutoDewV2SP, nullptr);
1553 }
1554 }
1555
1556 lastSensorData = result;
1557 return true;
1558 }
1559
1560 return false;
1561 }
1562
1563 //////////////////////////////////////////////////////////////////////
1564 ///
1565 //////////////////////////////////////////////////////////////////////
getPowerData()1566 bool PegasusUPB::getPowerData()
1567 {
1568 char res[PEGASUS_LEN] = {0};
1569 if (sendCommand("PC", res))
1570 {
1571 std::vector<std::string> result = split(res, ":");
1572 if ( (version == UPB_V1 && result.size() != 3) ||
1573 (version == UPB_V2 && result.size() != 4))
1574 {
1575 LOGF_WARN("Received wrong number (%i) of power sensor data (%s). Retrying...", result.size(), res);
1576 return false;
1577 }
1578
1579 if (result == lastPowerData)
1580 return true;
1581
1582 PowerConsumptionN[CONSUMPTION_AVG_AMPS].value = std::stod(result[0]);
1583 PowerConsumptionN[CONSUMPTION_AMP_HOURS].value = std::stod(result[1]);
1584 PowerConsumptionN[CONSUMPTION_WATT_HOURS].value = std::stod(result[2]);
1585 PowerConsumptionNP.s = IPS_OK;
1586 IDSetNumber(&PowerConsumptionNP, nullptr);
1587
1588 if (version == UPB_V2)
1589 {
1590 try
1591 {
1592 std::chrono::milliseconds uptime(std::stol(result[3]));
1593 using dhours = std::chrono::duration<double, std::ratio<3600>>;
1594 std::stringstream ss;
1595 ss << std::fixed << std::setprecision(3) << dhours(uptime).count();
1596 IUSaveText(&FirmwareT[FIRMWARE_UPTIME], ss.str().c_str());
1597 }
1598 catch(...)
1599 {
1600 IUSaveText(&FirmwareT[FIRMWARE_UPTIME], "NA");
1601 LOGF_WARN("Failed to process uptime: %s", result[3].c_str());
1602 return false;
1603 }
1604 IDSetText(&FirmwareTP, nullptr);
1605 }
1606
1607 lastPowerData = result;
1608 return true;
1609 }
1610
1611 return false;
1612 }
1613
1614 //////////////////////////////////////////////////////////////////////
1615 ///
1616 //////////////////////////////////////////////////////////////////////
getStepperData()1617 bool PegasusUPB::getStepperData()
1618 {
1619 char res[PEGASUS_LEN] = {0};
1620 if (sendCommand("SA", res))
1621 {
1622 std::vector<std::string> result = split(res, ":");
1623 if (result.size() != 4)
1624 {
1625 LOGF_WARN("Received wrong number (%i) of stepper sensor data (%s). Retrying...", result.size(), res);
1626 return false;
1627 }
1628
1629 if (result == lastStepperData)
1630 return true;
1631
1632 FocusAbsPosN[0].value = std::stoi(result[0]);
1633 focusMotorRunning = (std::stoi(result[1]) == 1);
1634
1635 if (FocusAbsPosNP.s == IPS_BUSY && focusMotorRunning == false)
1636 {
1637 FocusAbsPosNP.s = IPS_OK;
1638 FocusRelPosNP.s = IPS_OK;
1639 IDSetNumber(&FocusAbsPosNP, nullptr);
1640 IDSetNumber(&FocusRelPosNP, nullptr);
1641 }
1642 else if (result[0] != lastStepperData[0])
1643 IDSetNumber(&FocusAbsPosNP, nullptr);
1644
1645 FocusReverseS[INDI_ENABLED].s = (std::stoi(result[2]) == 1) ? ISS_ON : ISS_OFF;
1646 FocusReverseS[INDI_DISABLED].s = (std::stoi(result[2]) == 1) ? ISS_OFF : ISS_ON;
1647
1648 if (result[2] != lastStepperData[2])
1649 IDSetSwitch(&FocusReverseSP, nullptr);
1650
1651 uint16_t backlash = std::stoi(result[3]);
1652 if (backlash == 0)
1653 {
1654 FocusBacklashN[0].value = backlash;
1655 FocusBacklashS[INDI_ENABLED].s = ISS_OFF;
1656 FocusBacklashS[INDI_DISABLED].s = ISS_ON;
1657 if (result[3] != lastStepperData[3])
1658 {
1659 IDSetSwitch(&FocusBacklashSP, nullptr);
1660 IDSetNumber(&FocuserSettingsNP, nullptr);
1661 }
1662 }
1663 else
1664 {
1665 FocusBacklashS[INDI_ENABLED].s = ISS_ON;
1666 FocusBacklashS[INDI_DISABLED].s = ISS_OFF;
1667 FocusBacklashN[0].value = backlash;
1668 if (result[3] != lastStepperData[3])
1669 {
1670 IDSetSwitch(&FocusBacklashSP, nullptr);
1671 IDSetNumber(&FocuserSettingsNP, nullptr);
1672 }
1673 }
1674
1675 lastStepperData = result;
1676 return true;
1677 }
1678
1679 return false;
1680 }
getDewAggData()1681 bool PegasusUPB::getDewAggData()
1682 {
1683 char res[PEGASUS_LEN] = {0};
1684 if (sendCommand("DA", res))
1685 {
1686 std::vector<std::string> result = split(res, ":");
1687 if (result.size() != 2)
1688 {
1689 LOGF_WARN("Received wrong number (%i) of dew aggresiveness data (%s). Retrying...", result.size(), res);
1690 return false;
1691 }
1692
1693 if (result == lastDewAggData)
1694 return true;
1695
1696 AutoDewAggN[0].value = std::stod(result[1]);
1697 AutoDewAggNP.s = IPS_OK;
1698 IDSetNumber(&AutoDewAggNP, nullptr);
1699
1700 lastDewAggData = result;
1701 return true;
1702 }
1703 return false;
1704 }
1705 //////////////////////////////////////////////////////////////////////
1706 ///
1707 //////////////////////////////////////////////////////////////////////
reboot()1708 bool PegasusUPB::reboot()
1709 {
1710 return sendCommand("PF", nullptr);
1711 }
1712
1713 //////////////////////////////////////////////////////////////////////
1714 ///
1715 //////////////////////////////////////////////////////////////////////
split(const std::string & input,const std::string & regex)1716 std::vector<std::string> PegasusUPB::split(const std::string &input, const std::string ®ex)
1717 {
1718 // passing -1 as the submatch index parameter performs splitting
1719 std::regex re(regex);
1720 std::sregex_token_iterator
1721 first{input.begin(), input.end(), re, -1},
1722 last;
1723 return {first, last};
1724 }
1725
1726 //////////////////////////////////////////////////////////////////////
1727 ///
1728 //////////////////////////////////////////////////////////////////////
setupParams()1729 bool PegasusUPB::setupParams()
1730 {
1731 if (version == UPB_V2)
1732 getPowerOnBoot();
1733
1734 sendFirmware();
1735
1736 // Get Max Focuser Speed
1737 char res[PEGASUS_LEN] = {0};
1738 if (sendCommand("SS", res))
1739 {
1740 try
1741 {
1742 uint32_t value = std::stol(res);
1743 if (value == UINT16_MAX)
1744 {
1745 LOGF_WARN("Invalid maximum speed detected: %u. Please set maximum speed appropiate for your motor focus type (0-900)",
1746 value);
1747 FocuserSettingsNP.s = IPS_ALERT;
1748 }
1749 else
1750 {
1751 FocuserSettingsN[SETTING_MAX_SPEED].value = value;
1752 FocuserSettingsNP.s = IPS_OK;
1753 }
1754 }
1755 catch(...)
1756 {
1757 LOGF_WARN("Failed to process focuser max speed: %s", res);
1758 FocuserSettingsNP.s = IPS_ALERT;
1759 }
1760 }
1761
1762 return false;
1763 }
1764
1765 //////////////////////////////////////////////////////////////////////
1766 ///
1767 //////////////////////////////////////////////////////////////////////
cleanupResponse(char * response)1768 void PegasusUPB::cleanupResponse(char *response)
1769 {
1770 std::string s(response);
1771 s.erase(std::remove_if(s.begin(), s.end(),
1772 [](unsigned char x)
1773 {
1774 return std::isspace(x);
1775 }), s.end());
1776 strncpy(response, s.c_str(), PEGASUS_LEN);
1777 }
1778