Instrument Neutral Distributed Interface INDI 2.2.5
mydcp4esp32.cpp
Go to the documentation of this file.
1/*
2 myDCP4ESP32
3 Copyright (C) 2023 Stephen Hillier
4
5 Based on MyFocuserPro2 Focuser
6 Copyright (C) 2019 Alan Townshend
7
8 As well as USB_Dewpoint
9 Copyright (C) 2017-2023 Jarno Paananen
10
11 And INDI Sky Quality Meter Driver
12 Copyright(c) 2016 Jasem Mutlaq. All rights reserved.
13
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 2.1 of the License, or (at your option) any later version.
18
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
28*/
29
30#include "mydcp4esp32.h"
33#include "indicom.h"
34
35#include <cstring>
36#include <string>
37#include <memory>
38
39#include <termios.h>
40#include <unistd.h>
41
42#define USBDEWPOINT_TIMEOUT 3
43
44std::unique_ptr<MyDCP4ESP> mydcp4esp(new MyDCP4ESP());
45
50
52{
53 DefaultDevice::initProperties();
54
55 /* Temperature Probe Found status */
56 TempProbeFoundSP[0].fill("PROBE1", "Probe 1", ISS_OFF);
57 TempProbeFoundSP[1].fill("PROBE2", "Probe 2", ISS_OFF);
58 TempProbeFoundSP[2].fill("PROBE3", "Probe 3", ISS_OFF);
59 TempProbeFoundSP[3].fill("PROBE4", "Probe 4", ISS_OFF);
60 TempProbeFoundSP.fill(getDeviceName(), "SENSORS", "Sensors", MAIN_CONTROL_TAB, IP_RO, ISR_NOFMANY, 0, IPS_IDLE);
61
62 /* Temperatures */
63 TemperatureNP[0].fill("CHANNEL1", "Channel 1", "%3.2f", -50., 120., 0., 0.);
64 TemperatureNP[1].fill("CHANNEL2", "Channel 2", "%3.2f", -50., 120., 0., 0.);
65 TemperatureNP[2].fill("CHANNEL3", "Channel 3", "%3.2f", -50., 120., 0., 0.);
66 TemperatureNP[3].fill("CHANNEL4", "Channel 4", "%3.2f", -50., 120., 0., 0.);
67 TemperatureNP.fill(getDeviceName(), "TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
68
69 /* Ambient Temperature */
70 AmbientTemperatureNP[0].fill("AMBIENT", "Ambient", "%3.2f", 0., 100., 0., 0.);
71 AmbientTemperatureNP.fill(getDeviceName(), "AMBIENT", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
72
73 /* Humidity */
74 HumidityNP[0].fill("HUMIDITY", "Humidity", "%3.2f", 0., 100., 0., 0.);
75 HumidityNP.fill(getDeviceName(), "HUMIDITY", "Humidity", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
76
77 /* Dew point */
78 DewpointNP[0].fill("DEWPOINT", "Dew point", "%3.2f", -50., 120., 0., 0.);
79 DewpointNP.fill(getDeviceName(), "DEWPOINT", "Dew point", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
80
81 /* Temperature calibration values */
82 ChannelOffsetNP[0].fill("CHANNEL1", "Channel 1", "%1.2f", -5., 5., 0.25, 0.);
83 ChannelOffsetNP[1].fill("CHANNEL2", "Channel 2", "%1.2f", -5., 5., 0.25, 0.);
84 ChannelOffsetNP[2].fill("CHANNEL3", "Channel 3", "%1.2f", -5., 5., 0.25, 0.);
85 ChannelOffsetNP[3].fill("CHANNEL4", "Channel 4", "%1.2f", -5., 5., 0.25, 0.);
86 ChannelOffsetNP.fill(getDeviceName(), "TEMPOFFSET", "T Offset", OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
87
88 /* Ambient Temperature Offset */
89 AmbientOffsetNP[0].fill("AMBIENT", "Ambient", "%1.2f", -4., 3., 0.25, 0.);
90 AmbientOffsetNP.fill(getDeviceName(), "AMBIENTOFFSET", "T Offset", OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
91
92 /* Tracking Offset */
93 TrackingOffsetNP[0].fill("TRACKING", "Tracking", "%1.0f", -4, 3, 1, 0);
94 TrackingOffsetNP.fill(getDeviceName(), "TRACKING", "T Offset", OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
95
96 /* Channel 3 operating Mode */
97 Ch3ModeSP[0].fill("DISABLED", "Disabled", ISS_OFF);
98 Ch3ModeSP[1].fill("CHANNEL1", "Channel 1", ISS_OFF);
99 Ch3ModeSP[2].fill("CHANNEL2", "Channel 2", ISS_OFF);
100 Ch3ModeSP[3].fill("MANUAL", "Manual", ISS_OFF);
101 Ch3ModeSP[4].fill("CHANNEL3", "Channel 3", ISS_ON);
102 Ch3ModeSP.fill(getDeviceName(), "CH3MODE", "Ch3 Mode", DEW_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
103
104 /* Tracking Mode (Ambient, Dewpoint, Midpoint) */
105 TrackingModeSP[0].fill("AMBIENT", "Ambient", ISS_OFF);
106 TrackingModeSP[1].fill("DEWPOINT", "Dewpoint", ISS_OFF);
107 TrackingModeSP[2].fill("MIDPOINT", "Midpoint", ISS_OFF);
108 TrackingModeSP.fill(getDeviceName(), "TRACKING_MODE", "Tracking Mode", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
109
110 /* Channel 100% Boost On/Off */
111 ChannelBoostSP[0].fill("CHANNEL1", "Channel 1", ISS_OFF);
112 ChannelBoostSP[1].fill("CHANNEL2", "Channel 2", ISS_OFF);
113 ChannelBoostSP[2].fill("CHANNEL3", "Channel 3", ISS_OFF);
114 ChannelBoostSP[3].fill("CHANNEL4", "Channel 4", ISS_OFF);
115 ChannelBoostSP[4].fill("RESETALL", "Reset All", ISS_OFF);
116 ChannelBoostSP.fill(getDeviceName(), "CHANNELBOOST", "100% Boost", DEW_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE);
117
118
119 /* Firmware version */
120 FWversionNP[0].fill("FIRMWARE", "Firmware Version", "%3.0f", 0, 999, 0, 0);
121 FWversionNP.fill(getDeviceName(), "FW_VERSION", "Firmware", CONNECTION_TAB, IP_RO, 0, IPS_IDLE);
122
123 /* Controller check code */
124 CheckCodeTP[0].fill("CNTR_CODE", "Handshake Code", nullptr);
125 CheckCodeTP.fill(getDeviceName(), "CNTR_CODE", "Controller", CONNECTION_TAB, IP_RO, 0, IPS_IDLE);
126
128
131
136
137 // No simulation control for now
138
139 if (mdcpConnection & CONNECTION_SERIAL)
140 {
141 serialConnection = new Connection::Serial(this);
142 serialConnection->registerHandshake([&]()
143 {
144 return Handshake();
145 });
147 registerConnection(serialConnection);
148 }
149
150 if (mdcpConnection & CONNECTION_TCP)
151 {
152 tcpConnection = new Connection::TCP(this);
153 tcpConnection->setDefaultHost("192.168.4.1");
154 tcpConnection->setDefaultPort(3131);
155 tcpConnection->registerHandshake([&]()
156 {
157 return Handshake();
158 });
159
160 registerConnection(tcpConnection);
161 }
162
163
164 return true;
165}
166
168{
169 DefaultDevice::updateProperties();
171
172 if (isConnected())
173 {
174 // Main Control Tab
175 defineProperty(TrackingModeSP);
176 defineProperty(AmbientTemperatureNP);
177 defineProperty(HumidityNP);
178 defineProperty(DewpointNP);
179 defineProperty(TempProbeFoundSP);
180 defineProperty(TemperatureNP);
181 // Options Tab
182 if (myDCP4Firmware > 109) // Firmware 109 has a bug with setting Tracking offsets
183 defineProperty(TrackingOffsetNP);
184 defineProperty(AmbientOffsetNP);
185 defineProperty(ChannelOffsetNP);
186 // Connection Tab
187 defineProperty(FWversionNP);
188 defineProperty(CheckCodeTP);
189 // Dew Tab
190 if (myDCP4Firmware > 109) // Firmware 109 has a bug with the 100% boost settings
191 defineProperty(ChannelBoostSP);
192 defineProperty(Ch3ModeSP);
193 loadConfig(true);
194 readSettings();
195 LOG_INFO("myDCP4ESP32 parameters updated, device ready for use.");
196 timerIndex = SetTimer(getCurrentPollingPeriod());
197 }
198 else
199 {
200 // Main Control Tab
201 deleteProperty(TrackingModeSP);
202 deleteProperty(AmbientTemperatureNP);
203 deleteProperty(HumidityNP);
204 deleteProperty(DewpointNP);
205 deleteProperty(TempProbeFoundSP);
206 deleteProperty(TemperatureNP);
207 // Options Tab
208 if (myDCP4Firmware > 109) // Firmware 109 has a bug with setting Tracking offsets
209 deleteProperty(TrackingOffsetNP);
210 deleteProperty(AmbientOffsetNP);
211 deleteProperty(ChannelOffsetNP);
212 // Connection Tab
213 deleteProperty(FWversionNP);
214 deleteProperty(CheckCodeTP);
215 // Dew Tab
216 if (myDCP4Firmware > 109) // Firmware 109 has a bug with the 100% boost settings
217 deleteProperty(ChannelBoostSP);
218 deleteProperty(Ch3ModeSP);
219 }
220
221 return true;
222}
223
225{
226 return "MyDCP4ESP32";
227}
228
229// sleep for a number of milliseconds
230int MyDCP4ESP::msleep( long duration)
231{
232 struct timespec ts;
233 int res;
234
235 if (duration < 0)
236 {
237 errno = EINVAL;
238 return -1;
239 }
240
241 ts.tv_sec = duration / 1000;
242 ts.tv_nsec = (duration % 1000) * 1000000;
243
244 do
245 {
246 res = nanosleep(&ts, &ts);
247 }
248 while (res && errno == EINTR);
249
250 return res;
251}
252
253bool MyDCP4ESP::sendCommand(const char *cmd, char *resp)
254{
255 int nbytes_written = 0, nbytes_read = 0, rc = -1;
256 char errstr[MAXRBUF];
257
258 LOGF_DEBUG("CMD <%s>", cmd);
259 tcflush(PortFD, TCIOFLUSH);
260 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
261 {
262 tty_error_msg(rc, errstr, MAXRBUF);
263 LOGF_ERROR("Error writing command %s: %s.", cmd, errstr);
264 return false;
265 }
266
267 // Small delay to allow controller to process command
268 msleep(MDCP_SMALL_DELAY);
269
270 if (resp)
271 {
272 if ((rc = tty_nread_section(PortFD, resp, MDCP_RESPONSE_LENGTH, '#', MDCP_READ_TIMEOUT, &nbytes_read)) != TTY_OK)
273 {
274 tty_error_msg(rc, errstr, MAXRBUF);
275 LOGF_ERROR("Error reading response for command <%s>: %s.", cmd, errstr);
276 return false;
277 }
278
279 if (nbytes_read < 2)
280 {
281 LOGF_ERROR("Invalid response <%s> for command <%s>.", resp, cmd);
282 return false;
283 }
284
285 LOGF_DEBUG("RESP <%s>", resp);
286 resp[nbytes_read - 1] = '\0'; // Strip "#" termination character
287 }
288
289 return true;
290}
291
292// Determine which of the 4 channels have temperature probes attached. Only those with probes can be active
293// except for Channel 3 which can mirrior Channels 1 & 2 or be controlled manually.
294// Check to see if each channel can be set to Override if it doesn't currently have a power output
295bool MyDCP4ESP::getActiveChannels()
296{
297 char cmd[MDCP_CMD_LENGTH] = {};
298 char resp[MDCP_RESPONSE_LENGTH] = {};
299 int output[4] = {0, 0, 0, 0};
300 int ok, i;
301 unsigned int channel_boost = 0;
302 unsigned int currentCh3Mode = 0;
303
304 // Default all channels to active in case channel testing fails
305 i = 0;
306 while (i <= 3)
307 {
308 channelActive[i] = 1;
309 TempProbeFoundSP[i].setState(ISS_ON);
310 i++;
311 }
312
313 TempProbeFoundSP.setState(IPS_IDLE); // Keep state Idle unless positive exit
314 TempProbeFoundSP.apply();
315
316 if (myDCP4Firmware > 109)
317 {
318
319 // Get current channel output to trim the test to those at zero
320 if (!sendCommand(MDCP_GET_ALL_CH_POWER_CMD, resp))
321 return false;
322
323 ok = sscanf(resp, MDCP_GET_ALL_CH_POWER_RES, &output[0], &output[1], &output[2], &output[3] );
324
325 if (ok == 4)
326 {
327
328 i = 0;
329
330 while (i <= 3 ) // Go through each channel
331 {
332
333 if ((output[i] == 0) || (i == 2)) // Only do test if Channel power is zero or is Channel 3 (i=2)
334 {
335 if (i == 2) // Channel 3 (i=2) is special and needs to be in use temp probe mode to test
336 {
337 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
338
339 if (!sendCommand(MDCP_GET_CH3_MODE_CMD, resp))
340 return false;
341
342 ok = sscanf(resp, MDCP_GET_CH3_MODE_RES, &currentCh3Mode);
343
344 if ((ok != 1) || (currentCh3Mode > 4))
345 return false;
346
347 if (currentCh3Mode != CH3MODE_CH3TEMP)
348 if (!setCh3Mode( CH3MODE_CH3TEMP ))
349 return false;
350 }
351
352 if (!setChannelBoost( i + 1, 1))
353 return false;
354
356
357 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
358
359 if (!sendCommand(cmd, resp))
360 return false;
361
362 ok = sscanf(resp, MDCP_GET_CH_OVERIDE_RES, &channel_boost);
363
364 if ((ok == 1) && (channel_boost == 0))
365 {
366 TempProbeFoundSP[i].setState(ISS_OFF);
367 channelActive[i] = 0;
368 }
369
370 if (!setChannelBoost( i + 1, 0))
371 return false;
372
373 if ((i == 2) && (currentCh3Mode != CH3MODE_CH3TEMP)) // Return Ch3 to previous mode
374 if (!setCh3Mode(currentCh3Mode))
375 return false;
376
377 }
378
379 i++;
380 }
381 }
382 else
383 return false;
384 }
385 else
386 return false;
387
388 TempProbeFoundSP.setState(IPS_OK);
389 TempProbeFoundSP.apply();
390
391 // Set AutoDewSP based on which temp probes are found
392 AutoDewSP.reset(); // All switches OFF
393 for (i = 0; i < 4; i++)
394 {
395 AutoDewSP[i].setState(TempProbeFoundSP[i].getState());
396 }
399
400 return true;
401}
402
403bool MyDCP4ESP::Handshake()
404{
405 if (getActiveConnection() == serialConnection)
406 {
407 PortFD = serialConnection->getPortFD();
408 }
409 else if (getActiveConnection() == tcpConnection)
410 {
411 PortFD = tcpConnection->getPortFD();
412 }
413
414 int tries = 2;
415 do
416 {
417 if (Ack())
418 {
419 LOG_INFO("myDCP4ESP32 is online. Getting device parameters...");
420 if (!getActiveChannels())
421 LOG_INFO("Could not determine active channels. Default to all active.");
422 return true;
423 }
424 LOG_INFO("Error retrieving data from myDCP4ESP32, retrying...");
425 }
426 while (--tries > 0 );
427
428 LOG_INFO("Error retrieving data from myDCP4ESP32, please ensure controller "
429 "is powered and the port is correct.");
430
431 return false;
432}
433
434bool MyDCP4ESP::Ack()
435{
436
437 char resp[MDCP_RESPONSE_LENGTH] = {};
438 int firmware;
439 char code[10] = {};
440
441
442 if (!sendCommand(MDCP_GET_CONTROLLER_CODE_CMD, resp))
443 return false;
444
445
446 int ok = sscanf(resp, MDCP_GET_CONTROLLER_CODE_RES, code);
447
448 if (ok != 1)
449 {
450 LOGF_ERROR("Get Handshake Code: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_CONTROLLER_CODE_CMD);
451 return false;
452 }
453
454 CheckCodeTP[0].setText(code);
455 CheckCodeTP.setState(IPS_OK);
456 CheckCodeTP.apply();
457
458 tcflush(PortFD, TCIOFLUSH);
459 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
460
461 if (!sendCommand(MDCP_GET_VERSION_CMD, resp))
462 return false;
463
464 ok = sscanf(resp, MDCP_GET_VERSION_RES, &firmware);
465
466 if (ok != 1)
467 {
468 LOGF_ERROR("Get Firmware Version: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_VERSION_CMD);
469 return false;
470 }
471
472 myDCP4Firmware = firmware;
473 FWversionNP[0].setValue(firmware);
474 FWversionNP.setState(IPS_OK);
475 FWversionNP.apply();
476 return true;
477}
478
479// Set the temperature offset for a channel
480bool MyDCP4ESP::setChannelOffset(unsigned int channel, float value)
481{
482 char cmd[MDCP_CMD_LENGTH] = {};
483
484 switch (channel)
485 {
486 case 1:
488 break;
489
490 case 2:
492 break;
493
494 case 3:
496 break;
497
498 case 4:
500 break;
501
502 default:
503 return false;
504 }
505
506 return sendCommand(cmd, nullptr);
507}
508
509// Set the offset for ambient temperature
510bool MyDCP4ESP::setAmbientOffset(float value)
511{
512 char cmd[MDCP_CMD_LENGTH] = {};
513
515 return sendCommand(cmd, nullptr);
516}
517
518// set or reset Channel override. Channel = 5 resets all channels
519bool MyDCP4ESP::setChannelBoost( unsigned int channel, unsigned int value)
520{
521 char cmd[MDCP_CMD_LENGTH] = {};
522 if ((channel == 5) || (value == 0))
523 {
524 snprintf(cmd, MDCP_CMD_LENGTH, MDCP_RESET_CH_100_CMD, channel);
525 return sendCommand(cmd, nullptr);
526 }
527 else if (channel != 5)
528 {
529 if (channel > 4)
530 {
531 LOG_ERROR("Invalid channel for setChannelBoost");
532 return false;
533 }
534 if (channel != 3)
535 {
536 if (TempProbeFoundSP[channel - 1].getState() == ISS_OFF)
537 {
538 LOGF_INFO("Cannot set 100%% boost for Channel %d as no temperature probe is attached.", channel);
539 return false;
540 }
541 } else
542 {
543 // Channel 3 must be in temp probe mode to set 100% boost
544 if (Ch3ModeSP.findOnSwitchIndex() != CH3MODE_CH3TEMP)
545 {
546 LOG_INFO("Cannot set 100%% boost for Channel 3 when Ch3 Mode is not set to Channel 3.");
547 return false;
548 }
549 }
550 snprintf(cmd, MDCP_CMD_LENGTH, MDCP_SET_CH_100_CMD, channel);
551 return sendCommand(cmd, nullptr);
552 }
553
554 return false;
555}
556
557// Set Tracking Mode (1=Ambient, 2=Dewpoint, 3=Midpoint)
558bool MyDCP4ESP::setTrackingMode(unsigned int value)
559{
560 char cmd[MDCP_CMD_LENGTH] = {};
561
563 return sendCommand(cmd, nullptr);
564}
565
566// Set the mode for Channel 3 control (0=disabled, 1=Channel 1, 2=Channel 2, 3=Manual, 4=use temp probe3)
567bool MyDCP4ESP::setCh3Mode(unsigned int value)
568{
569 char cmd[MDCP_CMD_LENGTH] = {};
570
571 // There is a bug in the MyDCP4ESP32 firmware that does not properly reset 100% boost if Channel 3 mode
572 // changes from Channel 3 temperature to another mode. So we reset Channel 3 boost here to be safe.
573 if (value != CH3MODE_CH3TEMP)
574 setChannelBoost(3, 0);
575
576 snprintf(cmd, MDCP_CMD_LENGTH, MDCP_SET_CH3_MODE_CMD, value);
577 return sendCommand(cmd, nullptr);
578}
579
580// Set Channel 3 power output - Channel 3 must be in Manual mode.
581bool MyDCP4ESP::setCh3Output(unsigned int value)
582{
583 char cmd[MDCP_CMD_LENGTH] = {};
584
586 return sendCommand(cmd, nullptr);
587}
588
589// Set Tracking Offset
590bool MyDCP4ESP::setTrackingOffset(int value)
591{
592 char cmd[MDCP_CMD_LENGTH] = {};
593
595 return sendCommand(cmd, nullptr);
596}
597
598// Reboot the Dew Controller then wait to reconnect
599bool MyDCP4ESP::rebootController()
600{
601 LOG_INFO("Rebooting Controller and Disconnecting.");
602 sendCommand(MDCP_REBOOT_CMD, nullptr);
603
604 if (!Disconnect())
605 LOG_INFO("Disconnect failed");
606 setConnected(false, IPS_IDLE);
608 LOG_INFO("Waiting 10 seconds before attempting to reconnect.");
609 RemoveTimer(timerIndex);
610
611 int i = 1;
612 do
613 {
614 sleep(10);
615 if (!Connect())
616 {
617 i++;
618 if (i <= 5)
619 LOGF_INFO("Could not reconnect waiting 10 seconds before attempt %d of 5.", i);
620 else
621 {
622 LOGF_ERROR("Could not reconnect after %d attempts", i - 1);
623 setConnected(false, IPS_OK);
624 }
625 }
626 else
627 {
628 i = 0;
629 setConnected(true, IPS_OK);
630 }
631 }
632 while ((i != 0) && (i <= 5));
633
634 return updateProperties();
635}
636
637bool MyDCP4ESP::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
638{
639 if (!dev || strcmp(dev, getDeviceName()))
640 return false;
641
642 // Process power-related switches via PowerInterface
643 if (INDI::PowerInterface::processSwitch(dev, name, states, names, n))
644 return readSettings();
645
646 if (ChannelBoostSP.isNameMatch(name))
647 {
648 if (states[4] == ISS_ON) // Reset all to ISS_OFF
649 {
650 setChannelBoost(5, 1);
651 }
652 else // Check current versus new state and only invoke for changes
653 {
654 for (int i = 0; i < 4; i++)
655 {
656 if (ChannelBoostSP[i].getState() != states[i] )
657 setChannelBoost(i+1, states[i]);
658 }
659
660 }
661 ChannelBoostSP.update(states, names, n);
662 ChannelBoostSP.setState(IPS_BUSY);
663 ChannelBoostSP.apply();
664 readSettings();
665 return true;
666 }
667
668 if (Ch3ModeSP.isNameMatch(name))
669 {
670 Ch3ModeSP.update(states, names, n);
671 Ch3ModeSP.setState(IPS_BUSY);
672 Ch3ModeSP.apply();
673 setCh3Mode(Ch3ModeSP.findOnSwitchIndex());
674 readSettings();
675 return true;
676 }
677
678 if (TrackingModeSP.isNameMatch(name))
679 {
680 TrackingModeSP.update(states, names, n);
681 TrackingModeSP.setState(IPS_BUSY);
682 TrackingModeSP.apply();
683 setTrackingMode(TrackingModeSP.findOnSwitchIndex() + 1);
684 readSettings();
685 return true;
686 }
687
688 return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
689}
690
691bool MyDCP4ESP::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
692{
693 if (!dev || strcmp(dev, getDeviceName()))
694 return false;
695
696 // Process power-related numbers via PowerInterface
697 if (INDI::PowerInterface::processNumber(dev, name, values, names, n))
698 return readSettings();
699
700 if (ChannelOffsetNP.isNameMatch(name))
701 {
702 ChannelOffsetNP.update(values, names, n);
703 ChannelOffsetNP.setState(IPS_BUSY);
704 ChannelOffsetNP.apply();
705 setChannelOffset(1, ChannelOffsetNP[0].getValue());
706 setChannelOffset(2, ChannelOffsetNP[1].getValue());
707 setChannelOffset(3, ChannelOffsetNP[2].getValue());
708 setChannelOffset(4, ChannelOffsetNP[3].getValue());
709 readSettings();
710 return true;
711 }
712
713 if (AmbientOffsetNP.isNameMatch(name))
714 {
715 AmbientOffsetNP.update(values, names, n);
716 AmbientOffsetNP.setState(IPS_BUSY);
717 AmbientOffsetNP.apply();
718 setAmbientOffset(AmbientOffsetNP[0].getValue());
719 readSettings();
720 return true;
721 }
722
723 if (TrackingOffsetNP.isNameMatch(name))
724 {
725 TrackingOffsetNP.update(values, names, n);
726 TrackingOffsetNP.setState(IPS_BUSY);
727 TrackingOffsetNP.apply();
728 setTrackingOffset(TrackingOffsetNP[0].getValue());
729 readSettings();
730 return true;
731 }
732
733 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
734}
735
736bool MyDCP4ESP::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
737{
738 if (!dev || strcmp(dev, getDeviceName()))
739 return false;
740
741 // Process power-related text via PowerInterface
742 if (INDI::PowerInterface::processText(dev, name, texts, names, n))
743 return readSettings();
744
745 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
746}
747
749{
750 DefaultDevice::saveConfigItems(fp);
752
753 // Save device-specific properties
754 ChannelOffsetNP.save(fp);
755 AmbientOffsetNP.save(fp);
756 TrackingOffsetNP.save(fp);
757 Ch3ModeSP.save(fp);
758 TrackingModeSP.save(fp);
759
760 return true;
761}
762
763bool MyDCP4ESP::readSettings()
764{
765 char resp[MDCP_RESPONSE_LENGTH] = {};
766 int ok = -1;
767 float temp1, temp2, temp3, temp4, temp_ambient, humidity, dewpoint;
768 unsigned int output1, output2, output3, output4;
769 float ambient_offset, offset1, offset2, offset3, offset4;
770 int tracking_offset;
771 unsigned int tracking_mode, ch3_mode, channel_boost;
772
773
774 // Get Ambient offset first
775 if (!sendCommand(MDCP_GET_AMBIENT_OFFSET_CMD, resp))
776 return false;
777
778 ok = sscanf(resp, MDCP_GET_AMBIENT_OFFSET_RES, &ambient_offset );
779
780 if (ok == 1)
781 {
782 AmbientOffsetNP[0].setValue(ambient_offset);
783 AmbientOffsetNP.setState(IPS_OK);
784 AmbientOffsetNP.apply();
785 }
786 else
787 LOGF_ERROR("Get Ambient Offset: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_AMBIENT_OFFSET_CMD);
788
789 // Get the Ambient Temperature
790 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
791
792 if (!sendCommand(MDCP_GET_AMBIENT_TEMPERATURE_CMD, resp))
793 return false;
794
795 ok = sscanf(resp, MDCP_GET_AMBIENT_TEMPERATURE_RES, &temp_ambient );
796
797 // Set Ambient temperature adjusted by offset
798 if (ok == 1)
799 {
800 AmbientTemperatureNP[0].setValue(temp_ambient + ambient_offset);
801 AmbientTemperatureNP.setState(IPS_OK);
802 AmbientTemperatureNP.apply();
803 }
804 else
805 LOGF_ERROR("Get Ambient Temperature: Response <%s> for Command <%s> not recognized.", resp,
807
808 // Get Humidity
809 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
810
811 if (!sendCommand(MDCP_GET_HUMIDITY_CMD, resp))
812 return false;
813
814 ok = sscanf(resp, MDCP_GET_HUMIDITY_RES, &humidity );
815
816 if (ok == 1)
817 {
818 HumidityNP[0].setValue(humidity);
819 HumidityNP.setState(IPS_OK);
820 HumidityNP.apply();
821 }
822 else
823 LOGF_ERROR("Get Humidity: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_HUMIDITY_CMD);
824
825 // Get Dew Point
826 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
827
828 if (!sendCommand(MDCP_GET_DEWPOINT_CMD, resp))
829 return false;
830
831 ok = sscanf(resp, MDCP_GET_DEWPOINT_RES, &dewpoint );
832
833 if (ok == 1)
834 {
835 DewpointNP[0].setValue(dewpoint);
836 DewpointNP.setState(IPS_OK);
837 DewpointNP.apply();
838 }
839 else
840 LOGF_ERROR("Get Dew point: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_DEWPOINT_CMD);
841
842
843 // Get Channel 3 Mode
844 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
845
846 if (!sendCommand(MDCP_GET_CH3_MODE_CMD, resp))
847 return false;
848
849 ok = sscanf(resp, MDCP_GET_CH3_MODE_RES, &ch3_mode );
850
851 if ((ok == 1) && (ch3_mode <= 4))
852 {
853 Ch3ModeSP.reset();
854 Ch3ModeSP[ch3_mode].setState(ISS_ON);
855 Ch3ModeSP.setState(IPS_OK);
856 Ch3ModeSP.apply();
857
858 // Update AutoDewSP based on Ch3ModeSP
859 // AutoDew for Chaneel 3 is enabled if Channel 3 mode is CH3TEMP and Probe exists
860 if ((ch3_mode == CH3MODE_CH3TEMP) && (TempProbeFoundSP[2].getState() == ISS_ON))
861 {
863 }
864 else
865 {
867 }
868 // Make sure other AutoDew channels reflect TempProbeFoundSP
869 AutoDewSP[0].setState(TempProbeFoundSP[0].getState());
870 AutoDewSP[1].setState(TempProbeFoundSP[1].getState());
871 AutoDewSP[3].setState(TempProbeFoundSP[3].getState());
874
875 // DewChannelsSP at this point too
876 // Dew channels cannot be manually set except for Channel 3 in manual mode
879 DewChannelsSP[2].setState(ch3_mode == CH3MODE_MANUAL ? ISS_ON : ISS_OFF);
883
884 }
885 else
886 LOGF_ERROR("Get Channel 3 Mode: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_CH3_MODE_CMD);
887
888 // Get Temperature offsets for all channels then use to set the channel temperatures
889 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
890
891 // Get offset values first
892 if (!sendCommand(MDCP_GET_ALL_CH_OFFSET_CMD, resp))
893 return false;
894
895 ok = sscanf(resp, MDCP_GET_ALL_CH_OFFSET_RES, &offset1, &offset2, &offset3, &offset4 );
896
897 if (ok == 4)
898 {
899 ChannelOffsetNP[0].setValue(offset1);
900 ChannelOffsetNP[1].setValue(offset2);
901 ChannelOffsetNP[2].setValue(offset3);
902 ChannelOffsetNP[3].setValue(offset4);
903 ChannelOffsetNP.setState(IPS_OK);
904 ChannelOffsetNP.apply();
905 }
906 else
907 LOGF_ERROR("Get Channel Offset: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_ALL_CH_OFFSET_CMD);
908
909 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
910
911 if (!sendCommand(MDCP_GET_CHANNEL_TEMPS_CMD, resp))
912 return false;
913
914 ok = sscanf(resp, MDCP_GET_CHANNEL_TEMPS_RES, &temp1, &temp2, &temp3, &temp4 );
915
916 // Display adjusted temperature with offset but only for Channels with Probes
917 // the controller returns zero for temp if no probe but will continue to return offset
918 // channelActive will be zero for channels with no probe
919 if (ok == 4)
920 {
921 TemperatureNP[0].setValue(temp1 + (offset1 * channelActive[0]));
922 TemperatureNP[1].setValue(temp2 + (offset2 * channelActive[1]));
923 // Channel 3 is special and setting depends on CH3Mode only show in CH3TEMP mode
924 if (Ch3ModeSP.findOnSwitchIndex() == CH3MODE_CH3TEMP)
925 TemperatureNP[2].setValue(temp3 + (offset3 * channelActive[2]));
926 else
927 TemperatureNP[2].setValue( 0 );
928
929 TemperatureNP[3].setValue(temp4 + (offset4 * channelActive[3]));
930 TemperatureNP.setState(IPS_OK);
931 TemperatureNP.apply();
932 }
933 else
934 LOGF_ERROR("Get Channel Temperatures: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_CHANNEL_TEMPS_CMD);
935
936 // Get Tracking Mode
937 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
938
939 if (!sendCommand(MDCP_GET_TRACKING_MODE_CMD, resp))
940 return false;
941
942 ok = sscanf(resp, MDCP_GET_TRACKING_MODE_RES, &tracking_mode );
943
944 if ((ok == 1) && (tracking_mode > 0) && (tracking_mode <= 3))
945 {
946 // Update TrackingModeSP based on tracking_mode (1-indexed to 0-indexed)
947 TrackingModeSP.reset();
948 TrackingModeSP[tracking_mode - 1].setState(ISS_ON);
949 TrackingModeSP.setState(IPS_OK);
950 TrackingModeSP.apply();
951 }
952 else
953 {
954 // If tracking mode is not recognized or invalid, set TrackingModeSP to OFF and AutoDewSP to OFF
955 TrackingModeSP.reset(); // All switches OFF
956 TrackingModeSP.setState(IPS_OK);
957 TrackingModeSP.apply();
958
959 AutoDewSP.reset(); // All switches OFF
962 LOGF_ERROR("Get Tracking Mode: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_TRACKING_MODE_CMD);
963 }
964
965 //Get Tracking Offset but Firmware 109 has a bug with setting offsets so only for >109
966 if (myDCP4Firmware > 109)
967 {
968 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
969
970 if (!sendCommand(MDCP_GET_TRACKING_OFFSET_CMD, resp))
971 return false;
972
973 ok = sscanf(resp, MDCP_GET_TRACKING_OFFSET_RES, &tracking_offset );
974
975 if (ok == 1)
976 {
977 TrackingOffsetNP[0].setValue(tracking_offset);
978 TrackingOffsetNP.setState(IPS_OK);
979 TrackingOffsetNP.apply();
980 }
981 else
982 LOGF_ERROR("Get Tracking Offset: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_TRACKING_OFFSET_CMD);
983
984 }
985
986 // Current Channel 100% boost state but only for firmware >109 due to firmware bug
987 if (myDCP4Firmware > 109)
988 {
989 // Always clear the Chennel Boost states including the reset all
990 ChannelBoostSP.reset();
991
992 for (int i = 1; i <= 4; i++)
993 {
994 char cmd[MDCP_CMD_LENGTH] = {};
995
997
998 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
999
1000 if (!sendCommand(cmd, resp))
1001 return false;
1002
1003 ok = sscanf(resp, MDCP_GET_CH_OVERIDE_RES, &channel_boost);
1004
1005 if ((ok == 1) && (channel_boost <= 1))
1006 {
1007 ChannelBoostSP[i - 1].setState( ((channel_boost == 1) ? ISS_ON : ISS_OFF) );
1008 }
1009 else
1010 LOGF_ERROR("Get Channel Overrides: Response <%s> for Command <%s> not recognized.", resp, cmd);
1011 }
1012
1013 ChannelBoostSP.setState(IPS_OK);
1014 ChannelBoostSP.apply();
1015 }
1016
1017 // Get Power output for all channels
1018 memset(resp, '\0', MDCP_RESPONSE_LENGTH);
1019
1020 if (!sendCommand(MDCP_GET_ALL_CH_POWER_CMD, resp))
1021 return false;
1022
1023 ok = sscanf(resp, MDCP_GET_ALL_CH_POWER_RES, &output1, &output2, &output3, &output4 );
1024
1025 if (ok == 4)
1026 {
1027 // Update PowerChannelsSP based on output values
1028 DewChannelDutyCycleNP[0].setValue(output1);
1029 DewChannelDutyCycleNP[1].setValue(output2);
1030 DewChannelDutyCycleNP[2].setValue(output3);
1031 DewChannelDutyCycleNP[3].setValue(output4);
1034 }
1035 else
1036 LOGF_ERROR("Get Power Outputs: Response <%s> for Command <%s> not recognized.", resp, MDCP_GET_ALL_CH_POWER_CMD);
1037
1038
1039 return true;
1040}
1041
1043{
1044 if (!isConnected())
1045 {
1046 return;
1047 }
1048
1049 // Get temperatures etc.
1050 readSettings();
1051 timerIndex = SetTimer(getCurrentPollingPeriod());
1052}
1053
1054// Power Interface Implementations
1055bool MyDCP4ESP::SetPowerPort(size_t port, bool enabled)
1056{
1057 INDI_UNUSED(port);
1058 INDI_UNUSED(enabled);
1059 // MyDCP4ESP does not support direct power port on/off control.
1060 return false;
1061}
1062
1063bool MyDCP4ESP::SetDewPort(size_t port, bool enabled, double dutyCycle)
1064{
1065 INDI_UNUSED(enabled);
1066 // MyDCP4ESP32 only supports setting the Dew port duty cycle manully with Channel 3 in Manual mode
1067 if (port == 2) // Channel 3 is port 2 (0-based index)
1068 {
1069 // Ensure Channel 3 is in Manual mode
1070 if (Ch3ModeSP.findOnSwitchIndex() == CH3MODE_MANUAL)
1071 {
1072 setCh3Output(static_cast<unsigned int>(dutyCycle));
1073 return true;
1074 }
1075 else
1076 {
1077 LOG_WARN("Channel 3 must be in Manual mode to set Dew port duty cycle.");
1078 }
1079 }
1080 else
1081 {
1082 LOGF_WARN("Dew port duty cycle cannot be set for Channel %zu.", port + 1);
1083 }
1084 return false;
1085}
1086
1087bool MyDCP4ESP::SetVariablePort(size_t port, bool enabled, double voltage)
1088{
1089 INDI_UNUSED(port);
1090 INDI_UNUSED(enabled);
1091 INDI_UNUSED(voltage);
1092 // MyDCP4ESP does not have variable voltage outputs.
1093 return false;
1094}
1095
1097{
1098 INDI_UNUSED(enabled);
1099 // MyDCP4ESP does not have LED toggle control.
1100 return false;
1101}
1102
1103bool MyDCP4ESP::SetAutoDewEnabled(size_t port, bool enabled)
1104{
1105 // AutoDew is set for all channels that have temperature probes attached
1106 // and cannot be disabled except for Channel 3 which can be set to manual.
1107 if (port == 2)
1108 {
1109 if (enabled && (TempProbeFoundSP[2].getState() == ISS_ON))
1110 {
1111 return setCh3Mode(CH3MODE_CH3TEMP);
1112 }
1113 else if (!enabled)
1114 {
1115 return setCh3Mode(CH3MODE_MANUAL);
1116 }
1117 LOG_INFO("AutoDew for Channel 3 can only be enabled if a temperature probe is attached.");
1118 return false;
1119 }
1120 else
1121 {
1122 LOGF_INFO("AutoDew cannot be enabled/disabled for Channel %zu.", port + 1);
1123 return false;
1124 }
1125 return false;
1126}
1127
1129{
1130 return rebootController();
1131}
1132
1133bool MyDCP4ESP::SetUSBPort(size_t port, bool enabled)
1134{
1135 INDI_UNUSED(port);
1136 INDI_UNUSED(enabled);
1137 // MyDCP4ESP does not have USB port toggle control.
1138 return false;
1139}
double humidity
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...
The TCP class manages connection with devices over the network via TCP/IP. Upon successful connection...
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
int getPortFD() const
bool isConnected() const
const char * getDeviceName() const
void addPollPeriodControl()
Add Polling period control to the driver.
void addConfigurationControl()
Add Configuration control to the driver.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
virtual bool Disconnect()
Disconnect from device.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
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 loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void RemoveTimer(int id)
Remove timer added with SetTimer.
Connection::Interface * getActiveConnection()
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
void addDebugControl()
Add Debug control to the driver.
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.
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::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 double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
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 fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
virtual bool SetAutoDewEnabled(size_t port, bool enabled) override
SetAutoDewEnabled Enable/disable automatic dew control.
virtual const char * getDefaultName() override
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool SetPowerPort(size_t port, bool enabled) override
SetPowerPort Set power port on/off.
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 CyclePower() override
CyclePower Cycle power to all ports.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool SetLEDEnabled(bool enabled) override
SetLEDEnabled Enable/disable power LEDs.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool SetDewPort(size_t port, bool enabled, double dutyCycle) override
SetDewPort Set DEW/Dew port duty cycle.
virtual bool SetUSBPort(size_t port, bool enabled) override
SetUSBPort Set USB port on/off.
virtual bool SetVariablePort(size_t port, bool enabled, double voltage) override
SetVariablePort Set variable voltage port.
@ CONNECTION_SERIAL
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
int errno
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
@ IP_RO
Definition indiapi.h:182
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_NOFMANY
Definition indiapi.h:173
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
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_WARN(fmt,...)
Definition indilogger.h:81
#define LOG_WARN(txt)
Definition indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
std::unique_ptr< MyDCP4ESP > mydcp4esp(new MyDCP4ESP())
#define MDCP_REBOOT_CMD
Definition mydcp4esp32.h:56
#define MDCP_SET_TRACKING_OFFSET_CMD
Definition mydcp4esp32.h:74
#define MDCP_SET_CH3_MANUAL_POWER_CMD
Definition mydcp4esp32.h:92
#define MDCP_GET_AMBIENT_OFFSET_RES
#define CDRIVER_VERSION_MAJOR
Definition mydcp4esp32.h:41
#define MDCP_GET_HUMIDITY_RES
#define MDCP_SET_TRACKING_MODE_CMD
Definition mydcp4esp32.h:58
#define MDCP_GET_VERSION_RES
Definition mydcp4esp32.h:98
#define MDCP_GET_TRACKING_OFFSET_CMD
Definition mydcp4esp32.h:59
#define CDRIVER_VERSION_MINOR
Definition mydcp4esp32.h:42
#define MDCP_GET_CHANNEL_TEMPS_RES
#define MDCP_GET_ALL_CH_OFFSET_CMD
Definition mydcp4esp32.h:83
#define MDCP_SET_CH2_OFFSET_CMD
Definition mydcp4esp32.h:79
#define MDCP_GET_ALL_CH_POWER_RES
#define MDCP_GET_AMBIENT_OFFSET_CMD
Definition mydcp4esp32.h:67
#define MDCP_GET_CH_OVERIDE_CMD
Definition mydcp4esp32.h:85
#define MDCP_SET_AMBIENT_OFFSET_CMD
Definition mydcp4esp32.h:68
#define MDCP_SET_CH3_OFFSET_CMD
Definition mydcp4esp32.h:80
#define MDCP_SET_CH_100_CMD
Definition mydcp4esp32.h:84
#define MDCP_RESET_CH_100_CMD
Definition mydcp4esp32.h:88
#define MDCP_GET_CH3_MODE_CMD
Definition mydcp4esp32.h:91
#define MDCP_GET_CH_OVERIDE_RES
#define MDCP_GET_TRACKING_OFFSET_RES
#define MDCP_GET_VERSION_CMD
Definition mydcp4esp32.h:55
#define MDCP_GET_ALL_CH_POWER_CMD
Definition mydcp4esp32.h:89
#define MDCP_GET_CH3_MODE_RES
#define MDCP_GET_CONTROLLER_CODE_RES
Definition mydcp4esp32.h:97
#define MDCP_GET_HUMIDITY_CMD
Definition mydcp4esp32.h:69
#define MDCP_GET_TRACKING_MODE_RES
#define MDCP_GET_TRACKING_MODE_CMD
Definition mydcp4esp32.h:57
#define MDCP_RESPONSE_LENGTH
Definition mydcp4esp32.h:96
#define MDCP_GET_AMBIENT_TEMPERATURE_RES
#define MDCP_GET_AMBIENT_TEMPERATURE_CMD
Definition mydcp4esp32.h:66
#define MDCP_GET_CHANNEL_TEMPS_CMD
Definition mydcp4esp32.h:77
#define MDCP_GET_DEWPOINT_RES
#define MDCP_SET_CH1_OFFSET_CMD
Definition mydcp4esp32.h:78
#define MDCP_GET_ALL_CH_OFFSET_RES
#define MDCP_GET_DEWPOINT_CMD
Definition mydcp4esp32.h:70
#define MDCP_CMD_LENGTH
Definition mydcp4esp32.h:52
#define MDCP_GET_CONTROLLER_CODE_CMD
Definition mydcp4esp32.h:54
#define MDCP_SET_CH4_OFFSET_CMD
Definition mydcp4esp32.h:81
#define MDCP_SET_CH3_MODE_CMD
Definition mydcp4esp32.h:90
Namespace to encapsulate INDI client, drivers, and mediator classes.
uint8_t cmd[4]
Definition pwc-ioctl.h:2