Instrument Neutral Distributed Interface INDI 2.2.5
pegasus_ppb.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2019-2026 Jasem Mutlaq. All rights reserved.
3
4 Pegasus Pocket 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_ppb.h"
26#include "indicom.h"
28
29#include <memory>
30#include <regex>
31#include <termios.h>
32#include <cstring>
33#include <sys/ioctl.h>
34
35// We declare an auto pointer to PegasusPPB.
36static std::unique_ptr<PegasusPPB> pocket_power_box(new PegasusPPB());
37
38PegasusPPB::PegasusPPB() : INDI::DefaultDevice(), INDI::WeatherInterface(this), INDI::PowerInterface(this)
39{
40 setVersion(1, 1);
41 lastSensorData.reserve(PA_N);
42}
43
45{
47
49
50 WI::initProperties(ENVIRONMENT_TAB, ENVIRONMENT_TAB);
51
53
57 // DSLR on/off
58 DSLRPowerSP[INDI_ENABLED].fill("INDI_ENABLED", "On", ISS_OFF);
59 DSLRPowerSP[INDI_DISABLED].fill("INDI_DISABLED", "Off", ISS_ON);
60 DSLRPowerSP.fill(getDeviceName(), "DSLR_POWER", "DSLR Power", MAIN_CONTROL_TAB, IP_RW,
62
63 // Reboot
64 RebootSP[0].fill("REBOOT", "Reboot Device", ISS_OFF);
65 RebootSP.fill(getDeviceName(), "REBOOT_DEVICE", "Device", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1,
66 60, IPS_IDLE);
67
71
72 // Power on Boot
73 PowerOnBootSP[POWER_PORT_1].fill("POWER_PORT_1", "Port 1", ISS_ON);
74 PowerOnBootSP[POWER_PORT_2].fill("POWER_PORT_2", "Port 2", ISS_ON);
75 PowerOnBootSP[POWER_PORT_3].fill("POWER_PORT_3", "Port 3", ISS_ON);
76 PowerOnBootSP[POWER_PORT_4].fill("POWER_PORT_4", "Port 4", ISS_ON);
77 PowerOnBootSP.fill(getDeviceName(), "POWER_ON_BOOT", "Power On Boot", MAIN_CONTROL_TAB,
79
83 addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
84 addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
85 addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
86 setCriticalParameter("WEATHER_TEMPERATURE");
87
91 serialConnection = new Connection::Serial(this);
92 serialConnection->registerHandshake([&]()
93 {
94 return Handshake();
95 });
96 registerConnection(serialConnection);
97
98 return true;
99}
100
102{
104
105 if (isConnected())
106 {
107 // Main Control
108 defineProperty(DSLRPowerSP);
109 defineProperty(PowerOnBootSP);
110 defineProperty(RebootSP);
111
114
115 setupComplete = true;
116 }
117 else
118 {
119 // Main Control
120 deleteProperty(DSLRPowerSP);
121 deleteProperty(PowerOnBootSP);
122 deleteProperty(RebootSP);
123
126
127 setupComplete = false;
128 }
129
130 return true;
131}
132
134{
135 return "Pegasus PPB";
136}
137
138bool PegasusPPB::Handshake()
139{
140 int tty_rc = 0, nbytes_written = 0, nbytes_read = 0;
141 char command[PEGASUS_LEN] = {0}, response[PEGASUS_LEN] = {0};
142
143 PortFD = serialConnection->getPortFD();
144
145 LOG_DEBUG("CMD <P#>");
146
147 tcflush(PortFD, TCIOFLUSH);
148 strncpy(command, "P#\n", PEGASUS_LEN);
149 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
150 {
151 char errorMessage[MAXRBUF];
152 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
153 LOGF_ERROR("Serial write error: %s", errorMessage);
154 return false;
155 }
156
157 // Try first with stopChar as the stop character
158 if ( (tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read)) != TTY_OK)
159 {
160 // Try 0xA as the stop character
161 if (tty_rc == TTY_OVERFLOW || tty_rc == TTY_TIME_OUT)
162 {
163 tcflush(PortFD, TCIOFLUSH);
164 tty_write_string(PortFD, command, &nbytes_written);
165 stopChar = 0xA;
166 tty_rc = tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read);
167 }
168
169 if (tty_rc != TTY_OK)
170 {
171 char errorMessage[MAXRBUF];
172 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
173 LOGF_ERROR("Serial read error: %s", errorMessage);
174 return false;
175 }
176 }
177
178 tcflush(PortFD, TCIOFLUSH);
179 response[nbytes_read - 1] = '\0';
180 LOGF_DEBUG("RES <%s>", response);
181
182 setupComplete = false;
183
186 // 1 DC port group (controls all 4 outputs together), 2 DEW ports, 0 Variable port, 1 Auto Dew port (global), 0 USB ports
187 PI::initProperties(POWER_TAB, 1, 2, 0, 1, 0);
188
189 return !strcmp(response, "PPB_OK");
190}
191
192bool PegasusPPB::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
193{
194 if (dev && !strcmp(dev, getDeviceName()))
195 {
196 // DSLR
197 if (DSLRPowerSP.isNameMatch(name))
198 {
199 DSLRPowerSP.update(states, names, n);
200 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
201 snprintf(cmd, PEGASUS_LEN, "P2:%d", (DSLRPowerSP[INDI_ENABLED].getState() == ISS_ON) ? 1 : 0);
202 DSLRPowerSP.setState(sendCommand(cmd, res) ? IPS_OK : IPS_ALERT);
203 DSLRPowerSP.apply();
204 return true;
205 }
206
207 // Reboot
208 if (RebootSP.isNameMatch(name))
209 {
210 RebootSP.setState(reboot() ? IPS_OK : IPS_ALERT);
211 RebootSP.apply();
212 LOG_INFO("Rebooting device...");
213 return true;
214 }
215
216 // Power on boot
217 if (PowerOnBootSP.isNameMatch(name))
218 {
219 PowerOnBootSP.update(states, names, n);
220 PowerOnBootSP.setState(setPowerOnBoot() ? IPS_OK : IPS_ALERT);
221 PowerOnBootSP.apply();
222 saveConfig(PowerOnBootSP);
223 return true;
224 }
225
226 // Process power-related switches via PowerInterface
227 if (PI::processSwitch(dev, name, states, names, n))
228 return true;
229 }
230
231 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
232}
233
234bool PegasusPPB::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
235{
236 if (dev && !strcmp(dev, getDeviceName()))
237 {
238 if (strstr(name, "WEATHER_"))
239 return WI::processNumber(dev, name, values, names, n);
240
241 // Process power-related numbers via PowerInterface
242 if (PI::processNumber(dev, name, values, names, n))
243 return true;
244 }
245 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
246}
247
248bool PegasusPPB::ISNewText(const char * dev, const char * name, char * texts[], char * names[], int n)
249{
250 if (dev && !strcmp(dev, getDeviceName()))
251 {
252 // Process power-related text via PowerInterface
253 if (PI::processText(dev, name, texts, names, n))
254 return true;
255 }
256
257 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
258}
259
260bool PegasusPPB::sendCommand(const char * cmd, char * res)
261{
262 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
263 char command[PEGASUS_LEN] = {0};
264 LOGF_DEBUG("CMD <%s>", cmd);
265
266 for (int i = 0; i < 2; i++)
267 {
268 tcflush(PortFD, TCIOFLUSH);
269 snprintf(command, PEGASUS_LEN, "%s\n", cmd);
270 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
271 continue;
272
273 if (!res)
274 {
275 tcflush(PortFD, TCIOFLUSH);
276 return true;
277 }
278
279 if ( (tty_rc = tty_nread_section(PortFD, res, PEGASUS_LEN, stopChar, PEGASUS_TIMEOUT, &nbytes_read)) != TTY_OK
280 || nbytes_read == 1)
281 continue;
282
283 tcflush(PortFD, TCIOFLUSH);
284 res[nbytes_read - 1] = '\0';
285 LOGF_DEBUG("RES <%s>", res);
286 return true;
287 }
288
289 if (tty_rc != TTY_OK)
290 {
291 char errorMessage[MAXRBUF];
292 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
293 LOGF_ERROR("Serial error: %s", errorMessage);
294 }
295
296 return false;
297}
298
299bool PegasusPPB::setAutoDewEnabled(bool enabled)
300{
301 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
302 snprintf(cmd, PEGASUS_LEN, "PD:%d", enabled ? 1 : 0);
303 if (sendCommand(cmd, res))
304 {
305 return (!strcmp(res, cmd));
306 }
307
308 return false;
309}
310
311bool PegasusPPB::setPowerEnabled(uint8_t port, bool enabled)
312{
313 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
314 snprintf(cmd, PEGASUS_LEN, "P%d:%d", port, enabled ? 1 : 0);
315 if (sendCommand(cmd, res))
316 {
317 return (!strcmp(res, cmd));
318 }
319
320 return false;
321}
322
323bool PegasusPPB::setPowerOnBoot()
324{
325 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
326 snprintf(cmd, PEGASUS_LEN, "PE:%d%d%d%d", PowerOnBootSP[POWER_PORT_1].getState() == ISS_ON ? 1 : 0,
327 PowerOnBootSP[POWER_PORT_2].getState() == ISS_ON ? 1 : 0,
328 PowerOnBootSP[POWER_PORT_3].getState() == ISS_ON ? 1 : 0,
329 PowerOnBootSP[POWER_PORT_4].getState() == ISS_ON ? 1 : 0);
330 if (sendCommand(cmd, res))
331 {
332 return (!strcmp(res, "PE:1"));
333 }
334
335 return false;
336}
337
338bool PegasusPPB::setDewPWM(uint8_t id, uint8_t value)
339{
340 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
341 snprintf(cmd, PEGASUS_LEN, "P%d:%03d", id, value);
342 snprintf(expected, PEGASUS_LEN, "P%d:%d", id, value);
343 if (sendCommand(cmd, res))
344 {
345 return (!strcmp(res, expected));
346 }
347
348 return false;
349}
350
352{
354
355 PowerOnBootSP.save(fp);
356
359
360 return true;
361}
362
364{
365 if (!isConnected() || setupComplete == false)
366 {
368 return;
369 }
370
371 getSensorData();
373}
374
375bool PegasusPPB::sendFirmware()
376{
377 char res[PEGASUS_LEN] = {0};
378 if (sendCommand("PV", res))
379 {
380 LOGF_INFO("Detected firmware %s", res);
381 return true;
382 }
383
384 return false;
385}
386
387bool PegasusPPB::getSensorData()
388{
389 char res[PEGASUS_LEN] = {0};
390 if (sendCommand("PA", res))
391 {
392 std::vector<std::string> result = split(res, ":");
393 if (result.size() < PA_N)
394 {
395 LOGF_WARN("Received wrong number of detailed sensor data. Expected at least %d, got %zu. Retrying...", PA_N, result.size());
396 return false;
397 }
398
399 if (result == lastSensorData)
400 return true;
401
402 try
403 {
404 // Power Sensors
405 if (result.size() > PA_VOLTAGE && result.size() > PA_CURRENT)
406 {
407 PI::PowerSensorsNP[PI::SENSOR_VOLTAGE].setValue(std::stod(result[PA_VOLTAGE]));
408 PI::PowerSensorsNP[PI::SENSOR_CURRENT].setValue(std::stod(result[PA_CURRENT]) / 65.0);
410 if (lastSensorData.size() > PA_CURRENT &&
411 (lastSensorData[PA_VOLTAGE] != result[PA_VOLTAGE] || lastSensorData[PA_CURRENT] != result[PA_CURRENT]))
413 }
414
415 // Environment Sensors
416 if (result.size() > PA_TEMPERATURE && result.size() > PA_HUMIDITY && result.size() > PA_DEW_POINT)
417 {
418 setParameterValue("WEATHER_TEMPERATURE", std::stod(result[PA_TEMPERATURE]));
419 setParameterValue("WEATHER_HUMIDITY", std::stod(result[PA_HUMIDITY]));
420 setParameterValue("WEATHER_DEWPOINT", std::stod(result[PA_DEW_POINT]));
421 if (lastSensorData.size() > PA_DEW_POINT &&
422 (lastSensorData[PA_TEMPERATURE] != result[PA_TEMPERATURE] ||
423 lastSensorData[PA_HUMIDITY] != result[PA_HUMIDITY] ||
424 lastSensorData[PA_DEW_POINT] != result[PA_DEW_POINT]))
425 {
430 }
431 }
432
433 // Power Channel (single port group controlling all 4 physical outputs together)
434 if (result.size() > PA_PORT_STATUS && !result[PA_PORT_STATUS].empty())
435 {
436 const std::string& portStatus = result[PA_PORT_STATUS];
437 if (PI::PowerChannelsSP.size() >= 1 && portStatus.length() > 0)
438 {
439 PI::PowerChannelsSP[0].setState((portStatus[0] == '1') ? ISS_ON : ISS_OFF);
440 if (lastSensorData.size() > PA_PORT_STATUS && lastSensorData[PA_PORT_STATUS] != result[PA_PORT_STATUS])
442 }
443 }
444
445 // DSLR Power Status (This is a specific power output, not a generic USB port)
446 if (result.size() > PA_DSLR_STATUS && !result[PA_DSLR_STATUS].empty())
447 {
448 int dslrStatus = std::stoi(result[PA_DSLR_STATUS]);
449 DSLRPowerSP[INDI_ENABLED].setState((dslrStatus == 1) ? ISS_ON : ISS_OFF);
450 DSLRPowerSP[INDI_DISABLED].setState((dslrStatus == 0) ? ISS_ON : ISS_OFF);
451 DSLRPowerSP.setState((dslrStatus == 1) ? IPS_OK : IPS_IDLE);
452 if (lastSensorData.size() > PA_DSLR_STATUS && lastSensorData[PA_DSLR_STATUS] != result[PA_DSLR_STATUS])
453 DSLRPowerSP.apply();
454 }
455
456 // Dew PWM (2 ports)
457 if (result.size() > PA_DEW_1 && result.size() > PA_DEW_2)
458 {
459 if (PI::DewChannelDutyCycleNP.size() >= 1)
460 PI::DewChannelDutyCycleNP[0].setValue(std::stod(result[PA_DEW_1]) / 255.0 * 100.0);
461 if (PI::DewChannelDutyCycleNP.size() >= 2)
462 PI::DewChannelDutyCycleNP[1].setValue(std::stod(result[PA_DEW_2]) / 255.0 * 100.0);
463 if (lastSensorData.size() > PA_DEW_2 &&
464 (lastSensorData[PA_DEW_1] != result[PA_DEW_1] || lastSensorData[PA_DEW_2] != result[PA_DEW_2]))
466 }
467
468 // Update Dew Channel switches based on actual power status
469 // If Auto Dew is enabled, it may turn channels on/off, so we need to reflect that
470 if (result.size() > PA_DEW_1 && result.size() > PA_DEW_2)
471 {
472 bool dewChannelChanged = false;
473 if (PI::DewChannelsSP.size() >= 1)
474 {
475 auto newState = (std::stoi(result[PA_DEW_1]) > 0) ? ISS_ON : ISS_OFF;
476 if (PI::DewChannelsSP[0].getState() != newState)
477 {
478 PI::DewChannelsSP[0].setState(newState);
479 dewChannelChanged = true;
480 }
481 }
482 if (PI::DewChannelsSP.size() >= 2)
483 {
484 auto newState = (std::stoi(result[PA_DEW_2]) > 0) ? ISS_ON : ISS_OFF;
485 if (PI::DewChannelsSP[1].getState() != newState)
486 {
487 PI::DewChannelsSP[1].setState(newState);
488 dewChannelChanged = true;
489 }
490 }
491 if (dewChannelChanged)
493 }
494
495 // Auto Dew (global)
496 if (result.size() > PA_AUTO_DEW && !result[PA_AUTO_DEW].empty())
497 {
498 if (PI::AutoDewSP.size() >= 1)
499 PI::AutoDewSP[0].setState((std::stoi(result[PA_AUTO_DEW]) == 1) ? ISS_ON : ISS_OFF);
500 if (lastSensorData.size() > PA_AUTO_DEW && lastSensorData[PA_AUTO_DEW] != result[PA_AUTO_DEW])
502 }
503
504 lastSensorData = result;
505 return true;
506 }
507 catch (const std::exception& e)
508 {
509 LOGF_ERROR("Error parsing sensor data: %s. Response was: %s", e.what(), res);
510 return false;
511 }
512 }
513
514 return false;
515}
516
517// Device Control
518bool PegasusPPB::reboot()
519{
520 return sendCommand("PF", nullptr);
521}
522
523std::vector<std::string> PegasusPPB::split(const std::string &input, const std::string &regex)
524{
525 // passing -1 as the submatch index parameter performs splitting
526 std::regex re(regex);
527 std::sregex_token_iterator
528 first{input.begin(), input.end(), re, -1},
529 last;
530 return {first, last};
531}
532
536bool PegasusPPB::SetPowerPort(size_t port, bool enabled)
537{
538 // Port numbers in interface are 0-based, but device expects 1-based
539 return setPowerEnabled(port + 1, enabled);
540}
541
542bool PegasusPPB::SetDewPort(size_t port, bool enabled, double dutyCycle)
543{
544 // DEW ports are 3, 4 for dew heaters A, B (device uses 1-based indexing)
545 // Convert duty cycle percentage (0-100) to 0-255 range
546 auto pwmValue = static_cast<uint8_t>(dutyCycle / 100.0 * 255.0);
547 return setDewPWM(port + 3, enabled ? pwmValue : 0);
548}
549
550bool PegasusPPB::SetVariablePort(size_t port, bool enabled, double voltage)
551{
552 INDI_UNUSED(port);
553 INDI_UNUSED(enabled);
554 INDI_UNUSED(voltage);
555 return false;
556}
557
559{
560 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
561 snprintf(cmd, PEGASUS_LEN, "PL:%d", enabled ? 1 : 0);
562 if (sendCommand(cmd, res))
563 {
564 return (!strcmp(res, cmd));
565 }
566 return false;
567}
568
569bool PegasusPPB::SetAutoDewEnabled(size_t port, bool enabled)
570{
571 INDI_UNUSED(port); // PPB only has global auto dew control
572 return setAutoDewEnabled(enabled);
573}
574
576{
577 return reboot();
578}
579
580bool PegasusPPB::SetUSBPort(size_t port, bool enabled)
581{
582 INDI_UNUSED(port);
583 INDI_UNUSED(enabled);
584 return false;
585}
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
bool isConnected() const
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
INDI::PropertySwitch DewChannelsSP
bool saveConfigItems(FILE *fp)
saveConfigItems Save power properties in config file
INDI::PropertySwitch AutoDewSP
void SetCapability(uint32_t cap)
SetPowerCapability sets the Power capabilities. All capabilities must be initialized.
INDI::PropertyNumber PowerSensorsNP
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process Power number properties.
void initProperties(const char *groupName, size_t nPowerPorts=0, size_t nDewPorts=0, size_t nVariablePorts=0, size_t nAutoDewPorts=0, size_t nUSBPorts=0)
Initialize Power properties. It is recommended to call this function within initProperties() of your ...
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process Power text properties.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process Power switch properties.
INDI::PropertySwitch PowerChannelsSP
INDI::PropertyNumber DewChannelDutyCycleNP
bool updateProperties()
updateProperties Define or Delete Power properties based on the connection status of the base device
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning, bool flipWarning=false)
Add a physical weather measurable parameter to the weather driver.
bool setCriticalParameter(std::string name)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
bool syncCriticalParameters()
Synchronize and update the state of all critical parameters.
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
INDI::PropertyNumber ParametersNP
void initProperties(const char *statusGroup, const char *paramsGroup)
Initialize focuser properties. It is recommended to call this function within initProperties() of you...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyLight critialParametersLP
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
virtual bool SetPowerPort(size_t port, bool enabled) override
Power Interface Implementations.
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
const char * getDefaultName() override
virtual bool SetVariablePort(size_t port, bool enabled, double voltage) override
SetVariablePort Set variable voltage port.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool CyclePower() override
CyclePower Cycle power to all ports.
virtual bool SetLEDEnabled(bool enabled) override
SetLEDEnabled Enable/disable power LEDs.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_NOFMANY
Definition indiapi.h:173
@ ISR_ATMOST1
Definition indiapi.h:172
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:759
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
@ TTY_TIME_OUT
Definition indicom.h:58
@ TTY_OVERFLOW
Definition indicom.h:62
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOGF_WARN(fmt,...)
Definition indilogger.h:81
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
Namespace to encapsulate INDI client, drivers, and mediator classes.
uint8_t cmd[4]
Definition pwc-ioctl.h:2