Instrument Neutral Distributed Interface INDI 2.2.5
Terrans_PowerBoxPro_V2.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2015 Jasem Mutlaq. All rights reserved.
3
4 TerransPowerBoxProV2
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 "config.h"
27
28#include "indicom.h"
30
31#include <cerrno>
32#include <cstring>
33#include <memory>
34#include <termios.h>
35#include <unistd.h>
36#include <inttypes.h>
37#include <sys/ioctl.h>
38
39// We declare an auto pointer to TerransPowerBoxProV2.
40static std::unique_ptr<TerransPowerBoxProV2> terranspowerboxprov2(new TerransPowerBoxProV2());
41
42#define CMD_LEN 8
43#define TIMEOUT 500
44#define TAB_INFO "Status"
45
46int get_count = 0;
47int init = 0;
48double ch1_shuntv = 0;
49double ch2_shuntv = 0;
50double ch3_shuntv = 0;
51double ch1_current = 0;
52double ch2_current = 0;
53double ch3_current = 0;
54double ch1_bus = 0;
55double ch2_bus = 0;
56double ch3_bus = 0;
57double ch1_w = 0;
58double ch2_w = 0;
59double ch3_w = 0;
60double chusb_w = 0;
61double humidity = 0;
62double temperature = 0;
63double dewPoint = 0;
64double mcu_temp = 0;
65
66
67TerransPowerBoxProV2::TerransPowerBoxProV2() : INDI::PowerInterface(this), INDI::WeatherInterface(this)
68{
69 setVersion(1, 1);
70}
71
73{
75
77
78 // Note: PI::initProperties will be called in Handshake() after device identification
80
82
83 // Retain MCUTempNP as it's not power-related
84 IUFillNumber(&MCUTempN[0], "MCU_Temp", "MCU Temperature (C)", "%.2f", 0, 200, 0.01, 0);
85 IUFillNumberVector(&MCUTempNP, MCUTempN, 1, getDeviceName(), "MCU_Temp", "MCU", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
86
90 addParameter("WEATHER_TEMPERATURE", "Temperature (C)", -15, 35, 15);
91 addParameter("WEATHER_HUMIDITY", "Humidity %", 0, 100, 15);
92 addParameter("WEATHER_DEWPOINT", "Dew Point (C)", 0, 100, 15);
93
97 serialConnection = new Connection::Serial(this);
98 serialConnection->registerHandshake([&]()
99 {
100 return Handshake();
101 });
103 registerConnection(serialConnection);
104
105 return true;
106}
107
109{
111
112 if (isConnected())
113 {
114 defineProperty(&MCUTempNP);
117 setupComplete = true;
118 }
119 else
120 {
121 deleteProperty(MCUTempNP.name);
124 setupComplete = false;
125 }
126
127 return true;
128}
129
136
137bool TerransPowerBoxProV2::Handshake()
138{
139 char res[CMD_LEN] = {0};
140 if (isSimulation())
141 {
142 LOGF_INFO("Connected successfuly to simulated %s.", getDeviceName());
143 // Set capabilities and initialize PI properties for simulation
146 PI::initProperties(POWER_TAB, 7, 0, 1, 0, 6);
147 return true;
148 }
149
150 for(int HS = 0 ; HS < 3 ; HS++)
151 {
152 if (sendCommand(">VR#", res))
153 {
154 if(!strcmp(res, "*TPPNNN"))
155 {
156 if (sendCommand(">VN#", res))
157 {
158 if(!strcmp(res, "*V001"))
159 {
160 LOG_INFO("Handshake successfully!");
161 // Set capabilities and initialize PI properties
164 PI::initProperties(POWER_TAB, 7, 0, 1, 0, 6);
165 return true;
166 }
167 else
168 {
169 LOG_INFO("The firmware version does not match the driver. Please use the latest firmware and driver!");
170 return false;
171 }
172 }
173 }
174 else
175 {
176 LOG_INFO("Handshake failed!");
177 LOG_INFO("Retry...");
178 }
179 }
180 }
181 LOG_INFO("Handshake failed!");
182 return false;
183}
184
185
187{
188 LOG_INFO("GET Name");
189 return "TerransPowerBoxProV2";
190}
191
192bool TerransPowerBoxProV2::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
193{
194 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
195 {
196 // Let PowerInterface handle its switches first
197 if (PI::processSwitch(dev, name, states, names, n))
198 return true;
199
200 if (processButtonSwitch(dev, name, states, names, n))
201 return true;
202 }
203 return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
204}
205
206bool TerransPowerBoxProV2::ISNewText(const char * dev, const char * name, char * texts[], char * names[], int n)
207{
208 if (dev && !strcmp(dev, getDeviceName()))
209 {
210 // Let PowerInterface handle its text properties
211 if (PI::processText(dev, name, texts, names, n))
212 return true;
213 }
214 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
215}
216
217bool TerransPowerBoxProV2::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
218{
219 if (dev && !strcmp(dev, getDeviceName()))
220 {
221 // Let PowerInterface handle its number properties
222 if (PI::processNumber(dev, name, values, names, n))
223 return true;
224 }
225 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
226}
227
228bool TerransPowerBoxProV2::sendCommand(const char * cmd, char * res)
229{
230
231 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
232 char command[CMD_LEN] = {0};
233 PortFD = serialConnection->getPortFD();
234 LOGF_DEBUG("CMD <%s>", cmd);
235
236 for (int i = 0; i < 2; i++)
237 {
238 tcflush(PortFD, TCIOFLUSH);
239 snprintf(command, CMD_LEN, "%s", cmd);
240 if ( (tty_rc = tty_write_string(PortFD, command, &nbytes_written)) != TTY_OK)
241 continue;
242
243 if (!res)
244 {
245 tcflush(PortFD, TCIOFLUSH);
246 return true;
247 }
248
249 if ( (tty_rc = tty_nread_section(PortFD, res, CMD_LEN, '#', TIMEOUT, &nbytes_read)) != TTY_OK || nbytes_read == 1)
250 continue;
251
252 tcflush(PortFD, TCIOFLUSH);
253 res[nbytes_read - 1] = '\0';
254 LOGF_DEBUG("RES <%s>", res);
255 return true;
256 }
257
258 if (tty_rc != TTY_OK)
259 {
260 char errorMessage[MAXRBUF];
261 tty_error_msg(tty_rc, errorMessage, MAXRBUF);
262 LOGF_ERROR("Serial error: %s", errorMessage);
263 }
264
265 return false;
266}
267
269{
270 if (!isConnected() || setupComplete == false)
271 {
272 SetTimer(100);
273 return;
274 }
275
276 Get_State();
277 SetTimer(100);
278}
279
280void TerransPowerBoxProV2::Get_State()
281{
282 char res[CMD_LEN] = {0};
283 static bool powerChanged = false;
284 static bool usbChanged = false;
285
286 if(get_count == 0)
287 {
288 powerChanged = false; // Reset at start of power channel polling
289 if (sendCommand(">GDA#", res))
290 {
291 ISState newState = (!strcmp(res, "*DA1NNN")) ? ISS_ON : ISS_OFF;
292 if (PI::PowerChannelsSP[0].getState() != newState)
293 {
294 PI::PowerChannelsSP[0].setState(newState);
295 powerChanged = true;
296 }
297 }
298 get_count++;
299 }
300 else if(get_count == 1)
301 {
302 if (sendCommand(">GDB#", res))
303 {
304 ISState newState = (!strcmp(res, "*DB1NNN")) ? ISS_ON : ISS_OFF;
305 if (PI::PowerChannelsSP[1].getState() != newState)
306 {
307 PI::PowerChannelsSP[1].setState(newState);
308 powerChanged = true;
309 }
310 }
311 get_count++;
312 }
313 else if(get_count == 2)
314 {
315 if (sendCommand(">GDC#", res))
316 {
317 ISState newState = (!strcmp(res, "*DC1NNN")) ? ISS_ON : ISS_OFF;
318 if (PI::PowerChannelsSP[2].getState() != newState)
319 {
320 PI::PowerChannelsSP[2].setState(newState);
321 powerChanged = true;
322 }
323 }
324 get_count++;
325 }
326 else if(get_count == 3)
327 {
328 if (sendCommand(">GDD#", res))
329 {
330 ISState newState = (!strcmp(res, "*DD1NNN")) ? ISS_ON : ISS_OFF;
331 if (PI::PowerChannelsSP[3].getState() != newState)
332 {
333 PI::PowerChannelsSP[3].setState(newState);
334 powerChanged = true;
335 }
336 }
337 get_count++;
338 }
339 else if(get_count == 4)
340 {
341 if (sendCommand(">GDE#", res))
342 {
343 ISState newState = (!strcmp(res, "*DE1NNN")) ? ISS_ON : ISS_OFF;
344 if (PI::PowerChannelsSP[4].getState() != newState)
345 {
346 PI::PowerChannelsSP[4].setState(newState);
347 powerChanged = true;
348 }
349 }
350 get_count++;
351 }
352 else if(get_count == 5)
353 {
354 if (sendCommand(">GDF#", res))
355 {
356 ISState newState = (!strcmp(res, "*DF1NNN")) ? ISS_ON : ISS_OFF;
357 if (PI::PowerChannelsSP[5].getState() != newState)
358 {
359 PI::PowerChannelsSP[5].setState(newState);
360 powerChanged = true;
361 }
362 }
363 get_count++;
364 }
365 else if(get_count == 6)
366 {
367 if (sendCommand(">GDG#", res))
368 {
369 ISState newState = (!strcmp(res, "*DG1NNN")) ? ISS_ON : ISS_OFF;
370 if (PI::PowerChannelsSP[6].getState() != newState)
371 {
372 PI::PowerChannelsSP[6].setState(newState);
373 powerChanged = true;
374 }
375 }
376 if (powerChanged)
377 {
379 }
380 get_count++;
381 }
382 else if(get_count == 7)
383 {
384 usbChanged = false; // Reset at start of USB port polling
385 if (sendCommand(">GUA#", res))
386 {
387 ISState newState = (!strcmp(res, "*UA111N")) ? ISS_ON : ISS_OFF;
388 if (PI::USBPortSP[0].getState() != newState)
389 {
390 PI::USBPortSP[0].setState(newState);
391 usbChanged = true;
392 }
393 }
394 get_count++;
395 }
396 else if(get_count == 8)
397 {
398 if (sendCommand(">GUB#", res))
399 {
400 ISState newState = (!strcmp(res, "*UB111N")) ? ISS_ON : ISS_OFF;
401 if (PI::USBPortSP[1].getState() != newState)
402 {
403 PI::USBPortSP[1].setState(newState);
404 usbChanged = true;
405 }
406 }
407 get_count++;
408 }
409 else if(get_count == 9)
410 {
411 if (sendCommand(">GUC#", res))
412 {
413 ISState newState = (!strcmp(res, "*UC111N")) ? ISS_ON : ISS_OFF;
414 if (PI::USBPortSP[2].getState() != newState)
415 {
416 PI::USBPortSP[2].setState(newState);
417 usbChanged = true;
418 }
419 }
420 get_count++;
421 }
422 else if(get_count == 10)
423 {
424 if (sendCommand(">GUD#", res))
425 {
426 ISState newState = (!strcmp(res, "*UD111N")) ? ISS_ON : ISS_OFF;
427 if (PI::USBPortSP[3].getState() != newState)
428 {
429 PI::USBPortSP[3].setState(newState);
430 usbChanged = true;
431 }
432 }
433 get_count++;
434 }
435 else if(get_count == 11)
436 {
437 if (sendCommand(">GUE#", res))
438 {
439 ISState newState = (!strcmp(res, "*UE11NN")) ? ISS_ON : ISS_OFF;
440 if (PI::USBPortSP[4].getState() != newState)
441 {
442 PI::USBPortSP[4].setState(newState);
443 usbChanged = true;
444 }
445 }
446 get_count++;
447 }
448 else if(get_count == 12)
449 {
450 if (sendCommand(">GUF#", res))
451 {
452 ISState newState = (!strcmp(res, "*UF11NN")) ? ISS_ON : ISS_OFF;
453 if (PI::USBPortSP[5].getState() != newState)
454 {
455 PI::USBPortSP[5].setState(newState);
456 usbChanged = true;
457 }
458 }
459 if (usbChanged)
460 {
462 }
463 get_count++;
464 }
465 else if(get_count == 13)
466 {
467 if (sendCommand(">GS#", res))
468 {
469 // State save status - could be tracked separately if needed
470 }
471 get_count++;
472 }
473 else if(get_count == 14)
474 {
475 if (sendCommand(">GPF#", res))
476 {
477 ch3_bus = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
478 ch3_bus = ch3_bus * 8 / 1000;
480 chusb_w = ch3_w - ch2_w - ch1_w;
481 if (chusb_w <= 0)
482 {
483 chusb_w = 0;
484 }
485
488 }
489 get_count++;
490 }
491 else if(get_count == 15)
492 {
493 if (sendCommand(">GPE#", res))
494 {
495 ch3_shuntv = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
496 ch3_current = ch3_shuntv * 40 / 1000000 / 0.01;
498 chusb_w = ch3_w - ch2_w - ch1_w;
499 if (chusb_w <= 0)
500 {
501 chusb_w = 0;
502 }
503
508 PI::PowerChannelCurrentNP[2].setValue(ch3_current); // Assuming ch3 is port 2
509 }
510 get_count++;
511 }
512 else if(get_count == 16)
513 {
514 if (sendCommand(">GPC#", res))
515 {
516 ch2_shuntv = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
517 ch2_current = ch2_shuntv * 40 / 1000000 / 0.002;
519 chusb_w = ch3_w - ch2_w - ch1_w;
520 if (chusb_w <= 0)
521 {
522 chusb_w = 0;
523 }
524
525 PI::PowerChannelCurrentNP[1].setValue(ch2_current); // Assuming ch2 is port 1
526 }
527 get_count++;
528 }
529 else if(get_count == 17)
530 {
531 if (sendCommand(">GPA#", res))
532 {
533 ch1_shuntv = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
534 ch1_current = ch1_shuntv * 40 / 1000000 / 0.002;
536 chusb_w = ch3_w - ch2_w - ch1_w;
537 if (chusb_w <= 0)
538 {
539 chusb_w = 0;
540 }
541 PI::PowerChannelCurrentNP[0].setValue(ch1_current); // Assuming ch1 is port 0
544 }
545 get_count++;
546 }
547 else if(get_count == 18)
548 {
549 if (sendCommand(">GTC#", res))
550 {
551 mcu_temp = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
552 if (mcu_temp == 0)
553 {
554 MCUTempN[0].value = 0;
555 }
556 else
557 {
558 if (res[2] == 'A')
559 {
560 mcu_temp = mcu_temp / 100;
561 MCUTempN[0].value = mcu_temp;
562
563 }
564 else if (res[2] == 'B')
565 {
566 mcu_temp = mcu_temp / 100;
567 mcu_temp = mcu_temp * (-1);
568 MCUTempN[0].value = mcu_temp;
569 }
570 }
571 MCUTempNP.s = IPS_OK;
572 }
573 IDSetNumber(&MCUTempNP, nullptr);
574 get_count++;
575 }
576 else if(get_count == 19)
577 {
578 if (sendCommand(">GTH#", res))
579 {
580 humidity = (res[5] - 0x30) + ((res[4] - 0x30) * 10) + ((res[3] - 0x30) * 100) + ((res[2] - 0x30) * 1000);
581 if (humidity == 0)
582 {
583 setParameterValue("WEATHER_HUMIDITY", 0);
584 }
585 else
586 {
587 humidity = humidity / 100;
588 setParameterValue("WEATHER_HUMIDITY", humidity);
589 }
590 }
592 get_count++;
593 }
594 else if(get_count == 20)
595 {
596 if (sendCommand(">GTT#", res))
597 {
598 temperature = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
599 if (temperature == 0)
600 {
601 setParameterValue("WEATHER_TEMPERATURE", 0);
602 }
603 else
604 {
605 if (res[2] == 'A')
606 {
607 temperature = temperature / 100;
608 setParameterValue("WEATHER_TEMPERATURE", temperature);
609 }
610 else if (res[2] == 'B')
611 {
612 temperature = temperature / 100;
613 temperature = temperature * (-1);
614 setParameterValue("WEATHER_TEMPERATURE", temperature);
615 }
616 }
617 }
619 get_count++;
620 }
621 else if(get_count == 21)
622 {
623 if (sendCommand(">GTD#", res))
624 {
625 dewPoint = (res[6] - 0x30) + ((res[5] - 0x30) * 10) + ((res[4] - 0x30) * 100) + ((res[3] - 0x30) * 1000);
626 if (dewPoint == 0)
627 {
628 setParameterValue("WEATHER_DEWPOINT", 0);
629 }
630 else
631 {
632 if (res[2] == 'A')
633 {
634 dewPoint = dewPoint / 100;
635 setParameterValue("WEATHER_DEWPOINT", dewPoint);
636 }
637 else if (res[2] == 'B')
638 {
639 dewPoint = dewPoint / 100;
640 dewPoint = dewPoint * (-1);
641 setParameterValue("WEATHER_DEWPOINT", dewPoint);
642 }
643 }
645 }
647 get_count++;
648 }
649 else if(get_count == 22)
650 {
651 // Skip auto heater status for now
652 get_count++;
653 }
654 else if(get_count == 23)
655 {
656 // Skip auto heater status for now
657 get_count++;
658 }
659 else if(get_count == 24)
660 {
661 // Skip auto heater status for now
662 get_count = 0;
663 }
664 init = 1;
665}
666
667bool TerransPowerBoxProV2::processButtonSwitch(const char *dev, const char *name, ISState * states, char *names[], int n)
668{
669 INDI_UNUSED(dev);
670 INDI_UNUSED(name);
671 INDI_UNUSED(states);
672 INDI_UNUSED(names);
673 INDI_UNUSED(n);
674
675 // Auto heater handling would go here if needed
676 return false;
677}
678
679// Implement PowerInterface virtual methods
680bool TerransPowerBoxProV2::SetPowerPort(size_t port, bool enabled)
681{
682 char res[CMD_LEN] = {0};
683 const char* commands[][2] =
684 {
685 {">SDA1#", ">SDA0#"}, // Port 0: DC A
686 {">SDB1#", ">SDB0#"}, // Port 1: DC B
687 {">SDC1#", ">SDC0#"}, // Port 2: DC C
688 {">SDD1#", ">SDD0#"}, // Port 3: DC D
689 {">SDE1#", ">SDE0#"}, // Port 4: DC E
690 {">SDF1#", ">SDF0#"}, // Port 5: DC F
691 {">SDG1#", ">SDG0#"} // Port 6: DC 19V
692 };
693
694 if (port >= 7)
695 return false;
696
697 const char* cmd = enabled ? commands[port][0] : commands[port][1];
698
699 if (sendCommand(cmd, res))
700 {
701 // Verify response matches expected state
702 return true;
703 }
704
705 return false;
706}
707
708bool TerransPowerBoxProV2::SetDewPort(size_t port, bool enabled, double dutyCycle)
709{
710 INDI_UNUSED(port);
711 INDI_UNUSED(enabled);
712 INDI_UNUSED(dutyCycle);
713 // No dew ports on this device
714 return false;
715}
716
717bool TerransPowerBoxProV2::SetVariablePort(size_t port, bool enabled, double voltage)
718{
719 INDI_UNUSED(port);
720
721 if (!enabled)
722 {
723 sendCommand(">SA10#", nullptr);
724 return true;
725 }
726
727 // Map voltage to command
728 if (voltage < 7) // 5V
729 {
730 sendCommand(">SA20#", nullptr);
731 }
732 else if (voltage < 10.5) // 9V
733 {
734 sendCommand(">SA40#", nullptr);
735 }
736 else // 12V
737 {
738 sendCommand(">SA550#", nullptr);
739 }
740
741 return true;
742}
743
745{
746 INDI_UNUSED(enabled);
747 // Not implemented on this device
748 return false;
749}
750
751bool TerransPowerBoxProV2::SetAutoDewEnabled(size_t port, bool enabled)
752{
753 INDI_UNUSED(port);
754 INDI_UNUSED(enabled);
755 // No auto dew on this device
756 return false;
757}
758
760{
761 // Not implemented on this device
762 return false;
763}
764
765bool TerransPowerBoxProV2::SetUSBPort(size_t port, bool enabled)
766{
767 char res[CMD_LEN] = {0};
768 const char* commands[][2] =
769 {
770 {">SUA1A#", ">SUA0A#"}, // Port 0: USB A
771 {">SUB1A#", ">SUB0A#"}, // Port 1: USB B
772 {">SUC1A#", ">SUC0A#"}, // Port 2: USB C
773 {">SUD1A#", ">SUD0A#"}, // Port 3: USB D
774 {">SUE1A#", ">SUE0A#"}, // Port 4: USB E
775 {">SUF1A#", ">SUF0A#"} // Port 5: USB F
776 };
777
778 if (port >= 6)
779 return false;
780
781 const char* cmd = enabled ? commands[port][0] : commands[port][1];
782
783 if (sendCommand(cmd, res))
784 {
785 // Verify response matches expected state
786 return true;
787 }
788
789 return false;
790}
791
double mcu_temp
#define TIMEOUT
double ch1_shuntv
double humidity
double dewPoint
double temperature
#define CMD_LEN
double ch1_current
double mcu_temp
double ch3_w
double ch2_shuntv
double ch3_shuntv
double ch3_current
double ch3_bus
double ch1_w
double ch1_bus
double ch1_shuntv
double chusb_w
double ch2_w
double ch2_bus
double humidity
double dewPoint
double ch2_current
double temperature
double ch1_current
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 ...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
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 ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
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...
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
bool isSimulation() const
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.
bool saveConfigItems(FILE *fp)
saveConfigItems Save power properties in config file
void SetCapability(uint32_t cap)
SetPowerCapability sets the Power capabilities. All capabilities must be initialized.
INDI::PropertyNumber PowerSensorsNP
INDI::PropertyNumber PowerChannelCurrentNP
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::PropertySwitch USBPortSP
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 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.
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
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...
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.
virtual bool SetPowerPort(size_t port, bool enabled) override
SetPowerPort Set power port on/off.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool SetLEDEnabled(bool enabled) override
SetLEDEnabled Enable/disable power LEDs.
virtual bool CyclePower() override
CyclePower Cycle power to all ports.
virtual bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SetVariablePort(size_t port, bool enabled, double voltage) override
SetVariablePort Set variable voltage port.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual const char * getDefaultName() override
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_RO
Definition indiapi.h:182
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
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
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:490
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition indidevapi.c:398
#define INDI_UNUSED(x)
Definition indidevapi.h:132
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#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
char name[MAXINDINAME]
Definition indiapi.h:321