Instrument Neutral Distributed Interface INDI 2.2.5
scopedome_arduino.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 ScopeDome Dome INDI Driver
3
4 Copyright(c) 2017-2024 Jarno Paananen. All rights reserved.
5
6 based on:
7
8 ScopeDome Windows ASCOM driver version 5.1.30
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License version 2 as published by the Free Software Foundation.
13 .
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18 .
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23*******************************************************************************/
24
25#include "scopedome_arduino.h"
28#include "indicom.h"
29
30#include <termios.h>
31
32#include <cstring>
33
34#define SCOPEDOME_TIMEOUT 2
35#define SCOPEDOME_MAX_READS 10
36
37static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
38{
39 static_cast<std::string *>(userp)->append((char *)contents, size * nmemb);
40 return size * nmemb;
41}
42
44 : parent(driver), interface(iface)
45{
47 {
48 ethernet = false;
49 PortFD = static_cast<Connection::Serial*>(interface)->getPortFD();
50 }
51 else
52 {
53 ethernet = true;
54 curl_global_init(CURL_GLOBAL_ALL);
55 curl = curl_easy_init();
56 if (curl)
57 {
58 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
59 const INDI::PropertyText &credentials = parent->getCredentials();
60 curl_easy_setopt(curl, CURLOPT_USERNAME, credentials[0].getText());
61 curl_easy_setopt(curl, CURLOPT_PASSWORD, credentials[1].getText());
62
63 // (Ab)use TCP connection to get host and port (though port is not actually used)
64 auto tcp = static_cast<Connection::TCP*>(interface);
65 hostName = tcp->host();
66 port = tcp->port();
67 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
68 }
69 else
70 {
71 LOG_ERROR("Error initializing curl library");
72 }
73 }
74}
75
77{
78 if (ethernet)
79 {
80 curl_global_cleanup();
81 if (curl)
82 {
83 curl_easy_cleanup(curl);
84 curl = nullptr;
85 }
86 }
87}
88
90{
91 std::string res;
92 if(performCommand("getMode", res))
93 {
94 return (res == "MASTER"); // only master & slave mode is currently supported (not clamshell or rolloff root)
95 }
96 return false;
97}
98
99bool ScopeDomeArduino::performCommand(const std::string &command, std::string &response)
100{
101 if (ethernet)
102 {
103 if (curl)
104 {
105 std::string readBuffer;
106 char requestURL[MAXRBUF + 1];
107
108 // Write buffer
109 LOGF_DEBUG("write cmd: %s", command.c_str());
110
111 snprintf(requestURL, MAXRBUF, "http://%s/?%s", hostName.c_str(), command.c_str());
112
113 curl_easy_setopt(curl, CURLOPT_URL, requestURL);
114 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
115 curl_easy_perform(curl);
116
117 if(readBuffer.size() < 3)
118 {
119 LOGF_ERROR("Error reading: %s. Cmd: %s", readBuffer.c_str(), command.c_str());
120 return false;
121 }
122 // Response is in form command|status|response, strip \r\n
123 std::string resp(readBuffer.begin(), readBuffer.end() - 2);
124
125 auto split = splitString(resp, '|');
126
127 if (split.size() != 3)
128 {
129 LOGF_ERROR("Invalid response: %s. Cmd: %s", resp.c_str(), command.c_str());
130 return false;
131 }
132
133 if (split[1] != "OK")
134 {
135 LOGF_ERROR("Error from device: %s. Cmd: %s", resp.c_str(), command.c_str());
136 return false;
137 }
138 response = split[2];
139 LOGF_DEBUG("read response: %s", response.c_str());
140 return true;
141 }
142 else
143 {
144 return false;
145 }
146 }
147 else
148 {
149 int nbytes_written = 0, rc = -1;
150 char errstr[MAXRBUF];
151
152 if (command.length() == 0)
153 return false;
154
155 tcflush(PortFD, TCIOFLUSH);
156
157 // Write buffer
158 LOGF_DEBUG("write cmd: %s", command.c_str());
159
160 char lineBuf[MAXRBUF + 1];
161 snprintf(lineBuf, MAXRBUF, "%s\r\n", command.c_str());
162
163 if ((rc = tty_write_string(PortFD, lineBuf, &nbytes_written)) != TTY_OK)
164 {
165 tty_error_msg(rc, errstr, MAXRBUF);
166 LOGF_ERROR("Error writing command: %s. Cmd: %s", errstr, command.c_str());
167 return false;
168 }
169
170 int nbytes_read = 0;
171
172 // Read response
173 if ((rc = tty_nread_section(PortFD, lineBuf, MAXRBUF, '\n', SCOPEDOME_TIMEOUT, &nbytes_read)) != TTY_OK)
174 {
175 tty_error_msg(rc, errstr, MAXRBUF);
176 LOGF_ERROR("Error reading: %s. Cmd: %s", errstr, command.c_str());
177 return false;
178 }
179 lineBuf[nbytes_read] = 0;
180 int len = strlen(lineBuf);
181 if(len < 3)
182 {
183 LOGF_ERROR("Error reading: %s. Cmd: %s", errstr, command.c_str());
184 return false;
185 }
186 // Response is in form command|status|response, strip \n
187 std::string resp(lineBuf, strlen(lineBuf) - 1);
188
189 auto split = splitString(resp, '|');
190
191 if (split.size() != 3)
192 {
193 LOGF_ERROR("Invalid response: %s. Cmd: %s", lineBuf, command.c_str());
194 return false;
195 }
196
197 if (split[1] != "OK")
198 {
199 LOGF_ERROR("Error from device: %s. Cmd: %s", lineBuf, command.c_str());
200 return false;
201 }
202 response = split[2];
203 LOGF_DEBUG("read response: %s", response.c_str());
204 return true;
205 }
206}
207
208void ScopeDomeArduino::getFirmwareVersions(double &main, double &rotary)
209{
210 std::string res;
211 if(performCommand("getFirmwareVersion", res))
212 {
213 main = std::stod(res);
214 }
215
216 if(performCommand("slave=getFirmwareVersion", res))
217 {
218 rotary = std::stod(res);
219 }
220}
221
223{
224 std::string res;
225 stepsPerRevolution = 0;
226 if(performCommand("getCalibratedRotation", res))
227 {
228 stepsPerRevolution = std::stoi(res);
229 }
230 if(stepsPerRevolution == 0)
231 {
232 LOG_INFO("Step count read as zero, run calibration");
233 stepsPerRevolution = 3240;
234 }
235 return stepsPerRevolution;
236}
237
238
240{
241 std::string status;
242 if(!performCommand("getStatus", status))
243 {
244 return -1;
245 }
246
247 // Parse the string
248 // getStatus|OK|0:1:0:1:1:1:1:1;0.0000:1.0000:0.4399;32000;31.29:38.00:999.90:999.90:999.90:999.90:999.90:999.90:999.90;1009.21:999.90;0;5.09;1:1:1:1:1:1;0:0:0:0:0.0000:0.0000:0:0:0;0;126;1#0:1:1:1:1:1:1:1;0.0000:1.0000:0.4291;32000;32.31:39.00:999.90:999.90:999.90:999.90:999.90:999.90:999.90;1009.30:999.90;0;5.09;1:1:1:1:1:1;0:0:0:0:0.0000:0.0000:0:0:0;0;106;1#1:0:0:0
249 /*
250 get master+slave status in format:
251 <master digital inputs>;<master analog
252 inputs>;<master encoders>;<master
253 temperatures>;<master+slave
254 clouds>;<master Vcc>;<master
255 buttons>;<master relays>;<master loop
256 time>;<master fresh flag>#<slave digital
257 inputs>;<slave analog inputs>;<slave
258 encoders>;<slave temperatures>;<slave
259 clouds>;<slave Vcc>;<slave
260 buttons>;<slave relays>;<slave loop
261 time>;<slave fresh flag>#<flags>
262 */
263 auto parts = splitString(status, '#');
264 if(parts.size() == 3)
265 {
266 auto master = splitString(parts[0], ';');
267
268 if (master.size() == 12)
269 {
270 int i = 0;
271 for(auto &s : master)
272 {
273 LOGF_DEBUG("master %d: %s", i++, s.c_str());
274 }
275 i = 0;
276 auto digitalInputs = splitString(master[0], ':');
277
278 for(const auto &input : digitalInputs)
279 {
280 inputs[i++] = (input == "0"); // inverted for some reason
281 }
282
283 i = 0;
284 auto analogInputs = splitString(master[1], ':');
285 for(const auto &input : analogInputs)
286 {
287 sensors[i++] = std::stod(input);
288 }
289 rotaryEncoder = std::stoi(master[2]);
290 auto temperatures = splitString(master[3], ':');
291 for(const auto &temp : temperatures)
292 {
293 sensors[i++] = std::stod(temp);
294 }
295 auto pressure_humidity = splitString(master[4], ':');
296 for(const auto &value : pressure_humidity)
297 {
298 sensors[i++] = std::stod(value);
299 }
300 std::string clouds = master[5];
301 std::string vcc = master[6];
302 std::string buttons = master[7];
303 auto relayPWM = splitString(master[8], ':');
304 i = 0;
305 for(int r = 6; r < 9; r++)
306 {
307 relays[i++] = (relayPWM[r] == "1");
308 }
309 moving = (relayPWM[0] == "1" || relayPWM[1] == "1");
310 if(!moving && rotaryEncoder != previousEncoder) // Check if the dome is still moving from inertia
311 moving = true;
312 previousEncoder = rotaryEncoder;
313
314 std::string emergency = master[9];
315 std::string loopTime = master[10];
316 std::string freshFlag = master[11];
317
318 // Voltage 064V needs some adjustment
319 sensors[0] *= 10.0 * (5.0 / 0.1955);
320 }
321 /*
322 MASTER_INPD_DETECT_230LOSS:
323 MASTER_INPD_ENCODERA:
324 MASTER_INPD_HOMESENSOR:
325 MASTER_INPD_FREE1:
326 MASTER_INPD_FREE2:
327 MASTER_INPD_RAINSENSOR:
328 MASTER_INPD_CLOUDSENSOR:
329 MASTER_INPD_TELESCOPE_A_H;
330 MASTER_INPA_VOLTAGE064:
331 MASTER_INPA_T_PT100:
332 MASTER_INPA_T_PCB;
333 MASTER_ENCODER_A;
334 MASTER_THERMOMETER_PCB:
335 MASTER_BAROMETER_TEMPERATURE:
336 MASTER_THERMOMETER_ONEWIRE_MOTOR:
337 MASTER_THERMOMETER_ONEWIRE_OUTSIDE:
338 MASTER_THERMOMETER_ONEWIRE_MIRROR_1:
339 MASTER_THERMOMETER_ONEWIRE_MIRROR_2:
340 MASTER_HIGROMETER_TEMPERATURE:
341 MASTER_PIROMETER_AMBIENT:
342 MASTER_PIROMETER_SENSOR;
343 MASTER_BAROMETER_PRESSURE:
344 MASTER_HIGROMETER_HUMIDITY;
345 MASTER_CLOUDS;
346 MASTER_Vcc;
347 MASTER_BUTTON_CW:
348 MASTER_BUTTON_CCW:
349 MASTER_BUTTON_FREE1:
350 MASTER_BUTTON_FREE2:
351 MASTER_BUTTON_FREE3:
352 MASTER_BUTTON_PAIR;
353 MASTER_REL_CW:
354 MASTER_REL_CCW:
355 MASTER_REL_INBOX:
356 MASTER_REL_MOTOR:
357 MASTER_PWM_1:
358 MASTER_PWM_2:
359 MASTER_REL_FREE1:
360 MASTER_REL_FREE2:
361 MASTER_REL_FREE3;
362 MASTER_EMERGENCY;
363 MASTER_LOOP_TIME;
364 MASTER_FRESH_FLAG
365 */
366 auto slave = splitString(parts[1], ';');
367
368 if (slave.size() == 12)
369 {
370 int i = 0;
371 for(auto &s : slave)
372 {
373 LOGF_DEBUG("slave %d: %s", i++, s.c_str());
374 }
375
376 auto digitalInputs = splitString(slave[0], ':');
377 i = 8;
378 for(const auto &input : digitalInputs)
379 {
380 inputs[i++] = (input == "0"); // inverted for some reason
381 }
382 i = 14;
383 auto analogInputs = splitString(slave[1], ':');
384 for(const auto &input : analogInputs)
385 {
386 sensors[i++] = std::stod(input);
387 }
388 shutterEncoder = std::stoi(slave[2]);
389 auto temperatures = splitString(slave[3], ':');
390 for(const auto &temp : temperatures)
391 {
392 sensors[i++] = std::stod(temp);
393 }
394 auto pressure_humidity = splitString(slave[4], ':');
395 for(const auto &value : pressure_humidity)
396 {
397 sensors[i++] = std::stod(value);
398 }
399 std::string clouds = slave[5];
400 std::string vcc = slave[6];
401 std::string buttons = slave[7];
402 auto relayPWM = splitString(slave[8], ':');
403 i = 3;
404 for(int r = 6; r < 9; r++)
405 {
406 relays[i++] = (relayPWM[r] == "1");
407 }
408 std::string emergency = slave[9];
409 std::string loopTime = slave[10];
410 std::string freshFlag = slave[11];
411
412 // Voltage 064V needs some adjustment
413 sensors[14] *= 10.0 * (5.0 / 0.1955);
414 }
415
416 /*
417 SLAVE_INPD_DETECT_230LOSS:
418 SLAVE_INPD_ENCODERA:
419 SLAVE_INPD_HOMESENSOR:
420 SLAVE_INPD_OPEN1:
421 SLAVE_INPD_CLOSE1:
422 SLAVE_INPD_RAINSENSOR:
423 SLAVE_INPD_CLOUDSENSOR:
424 SLAVE_INPD_TELESCOPE_A_H;
425 SLAVE_INPA_VOLTAGE064:
426 SLAVE_INPA_T_PT100:
427 SLAVE_INPA_T_PCB;
428 SLAVE_ENCODER_A;
429 SLAVE_THERMOMETER_PCB:
430 SLAVE_BAROMETER_TEMPERATURE:
431 SLAVE_THERMOMETER_ONEWIRE_MOTOR:
432 SLAVE_THERMOMETER_ONEWIRE_OUTSIDE:
433 SLAVE_THERMOMETER_ONEWIRE_MIRROR_1:
434 SLAVE_THERMOMETER_ONEWIRE_MIRROR_2:
435 SLAVE_HIGROMETER_TEMPERATURE:
436 SLAVE_PIROMETER_AMBIENT:
437 SLAVE_PIROMETER_SENSOR;
438 SLAVE_BAROMETER_PRESSURE:
439 SLAVE_HIGROMETER_HUMIDITY;
440 SLAVE_CLOUDS;
441 SLAVE_Vcc;
442 SLAVE_BUTTON_CW:
443 SLAVE_BUTTON_CCW:
444 SLAVE_BUTTON_FREE1:
445 SLAVE_BUTTON_FREE2:
446 SLAVE_BUTTON_FREE3:
447 SLAVE_BUTTON_PAIR;
448 SLAVE_REL_OPEN1:
449 SLAVE_REL_CLOSE1:
450 SLAVE_REL_INBOX:
451 SLAVE_REL_MOTOR:
452 SLAVE_PWM_1:
453 SLAVE_PWM_2:
454 SLAVE_REL_FREE1:
455 SLAVE_REL_FREE2:
456 SLAVE_REL_FREE3;
457 SLAVE_EMERGENCY;
458 SLAVE_LOOP_TIME;
459 SLAVE_FRESH_FLAG
460 */
461
462 auto flags = splitString(parts[2], ':');
463 if (flags.size() == 4)
464 {
465 int i = 0;
466 for(auto &s : flags)
467 {
468 LOGF_DEBUG("flags %d: %s", i++, s.c_str());
469 }
470 rotaryLink = (flags[0] == "1");
471 homing = (flags[1] == "1");
472 moveShutterOnHome = (flags[2] == "1");
473 calibrating = (flags[3] == "1");
474 }
475 /*
476 IS_SLAVE_ONLINE:
477 IS_COMPLEX_COMMAND_FINDING_HOME:
478 IS_COMPLEX_COMMAND_MOVE_SHUTTER_ON_HOME:
479 IS_COMPLEX_COMMAND_CALIBRATING
480 */
481 }
482 else
483 {
484 LOGF_DEBUG("invalid status response: %s", status.c_str());
485 }
486 return 0;
487}
488
490{
491 uint32_t status = 0;
492 if(homing)
493 {
494 status |= STATUS_HOMING | STATUS_MOVING;
495 }
496 if(calibrating)
497 {
499 }
500 if(moving)
501 {
502 status |= STATUS_MOVING;
503 }
504 LOGF_DEBUG("getStatus: %x", status);
505 return status;
506}
507
508// Abstract versions
510{
511 bool state = false;
512
513 switch(input)
514 {
515 case HOME:
516 state = inputs[2];
517 break;
518 case OPEN1:
519 state = inputs[11];
520 break;
521 case CLOSED1:
522 state = inputs[12];
523 break;
524 case OPEN2:
525 case CLOSED2:
526 break;
527 case ROTARY_LINK:
528 state = rotaryLink;
529 break;
530 default:
531 LOG_ERROR("invalid input");
532 break;
533 }
534 return state ? ISS_ON : ISS_OFF;
535}
536
538{
539 std::string res;
540 switch(output)
541 {
542 case RESET:
543 // performCommand("resetSoft", res);
544 break;
545 case CW:
546 if(onOff == ISS_ON)
547 {
548 performCommand("moveDome=CW", res);
549 }
550 else
551 {
552 performCommand("stopDome", res);
553 }
554 break;
555 case CCW:
556 if(onOff == ISS_ON)
557 {
558 performCommand("moveDome=CCW", res);
559 }
560 else
561 {
562 performCommand("stopDome", res);
563 }
564 break;
565 default:
566 LOG_ERROR("invalid output");
567 return -1;
568 }
569 return 0;
570}
571
573{
574 // Make rotary encoder value similar to USB Card 2.1
575 return encoderBaseValue - rotaryEncoder;
576}
577
579{
580 // Make relative to home sensor position like with USB Card 2.1
581 return encoderBaseValue - rotaryEncoder;
582}
583
585{
586 return false;
587}
588
590{
591 std::string res;
592 performCommand("stopDome", res);
593 performCommand("stopShutter", res);
594}
595
597{
598 std::string res;
599 performCommand("calibrate", res);
600}
601
603{
604 std::string res;
605 performCommand("findHome", res);
606}
607
609{
610 std::string res;
611 switch(operation)
612 {
613 case OPEN_SHUTTER:
614 performCommand("moveShutter=OPEN", res);
615 break;
616 case CLOSE_SHUTTER:
617 performCommand("moveShutter=CLOSE", res);
618 break;
619 case STOP_SHUTTER:
620 performCommand("stopShutter", res);
621 break;
622 default:
623 LOG_ERROR("Unknown shutter operation");
624 break;
625 }
626}
627
629{
630 // Doesn't seem to be needed as the counter resets by itself when passing home
631 // std::string res;
632 // char cmd[32] = {0};
633 // snprintf(cmd, 31, "setEncoderA=%d", encoderBaseValue);
634 // performCommand(cmd, res);
635}
636
638{
639 std::string res;
640 if(steps < 0 )
641 {
642 char cmd[32] = {0};
643 snprintf(cmd, 31, "moveDome=CCW:%d", -steps);
644 performCommand(cmd, res);
645 }
646 else
647 {
648 char cmd[32] = {0};
649 snprintf(cmd, 31, "moveDome=CW:%d", steps);
650 performCommand(cmd, res);
651 }
652}
653
655{
656 return 28;
657}
658
660{
662 switch(index)
663 {
664 case 0:
665 info.propName = "VOLTAGE064";
666 info.label = "Master 64V";
667 info.format = "%3.2f";
668 info.minValue = 0;
669 info.maxValue = 100;
670 break;
671 case 1:
672 info.propName = "T_PT100";
673 info.label = "T_PT100";
674 info.format = "%3.2f";
675 info.minValue = -100;
676 info.maxValue = 100;
677 break;
678 case 2:
679 info.propName = "T_PCB";
680 info.label = "T_PCB";
681 info.format = "%3.2f";
682 info.minValue = -100;
683 info.maxValue = 100;
684 break;
685 case 3:
686 info.propName = "THERMOMETER_PCB";
687 info.label = "PCB thermometer";
688 info.format = "%3.2f";
689 info.minValue = -100;
690 info.maxValue = 100;
691 break;
692 case 4:
693 info.propName = "BAROMETER_TEMPERATURE";
694 info.label = "Barometer temperature";
695 info.format = "%3.2f";
696 info.minValue = -100;
697 info.maxValue = 100;
698 break;
699 case 5:
700 info.propName = "THERMOMETER_ONEWIRE_MOTOR";
701 info.label = "Motor temperature";
702 info.format = "%3.2f";
703 info.minValue = -100;
704 info.maxValue = 100;
705 break;
706 case 6:
707 info.propName = "THERMOMETER_ONEWIRE_OUTSIDE";
708 info.label = "Outside temperature";
709 info.format = "%3.2f";
710 info.minValue = -100;
711 info.maxValue = 100;
712 break;
713 case 7:
714 info.propName = "THERMOMETER_ONEWIRE_MIRROR_1";
715 info.label = "Mirror 1 temperature";
716 info.format = "%3.2f";
717 info.minValue = -100;
718 info.maxValue = 100;
719 break;
720 case 8:
721 info.propName = "THERMOMETER_ONEWIRE_MIRROR_2";
722 info.label = "Mirror 2 temperature";
723 info.format = "%3.2f";
724 info.minValue = -100;
725 info.maxValue = 100;
726 break;
727 case 9:
728 info.propName = "HIGROMETER_TEMPERATURE";
729 info.label = "Higrometer temperature";
730 info.format = "%3.2f";
731 info.minValue = -100;
732 info.maxValue = 100;
733 break;
734 case 10:
735 info.propName = "PIROMETER_AMBIENT";
736 info.label = "Pirometer ambient temperature";
737 info.format = "%3.2f";
738 info.minValue = -100;
739 info.maxValue = 100;
740 break;
741 case 11:
742 info.propName = "PIROMETER_SENSOR";
743 info.label = "Pirometer sensor temperature";
744 info.format = "%3.2f";
745 info.minValue = -100;
746 info.maxValue = 100;
747 break;
748 case 12:
749 info.propName = "BAROMETER_PRESSURE";
750 info.label = "Barometer pressure";
751 info.format = "%4.2f";
752 info.minValue = 0;
753 info.maxValue = 2000;
754 break;
755 case 13:
756 info.propName = "HIGROMETER_HUMIDITY";
757 info.label = "Higrometer humidity";
758 info.format = "%3.2f";
759 info.minValue = 0;
760 info.maxValue = 100;
761 break;
762 case 14:
763 info.propName = "S_VOLTAGE064";
764 info.label = "Slave 64V";
765 info.format = "%3.2f";
766 info.minValue = 0;
767 info.maxValue = 100;
768 break;
769 case 15:
770 info.propName = "S_T_PT100";
771 info.label = "Slave T_PT100";
772 info.format = "%3.2f";
773 info.minValue = -100;
774 info.maxValue = 100;
775 break;
776 case 16:
777 info.propName = "S_T_PCB";
778 info.label = "Slave T_PCB";
779 info.format = "%3.2f";
780 info.minValue = -100;
781 info.maxValue = 100;
782 break;
783 case 17:
784 info.propName = "S_THERMOMETER_PCB";
785 info.label = "Slave PCB thermometer";
786 info.format = "%3.2f";
787 info.minValue = -100;
788 info.maxValue = 100;
789 break;
790 case 18:
791 info.propName = "S_BAROMETER_TEMPERATURE";
792 info.label = "Slave barometer temperature";
793 info.format = "%3.2f";
794 info.minValue = -100;
795 info.maxValue = 100;
796 break;
797 case 19:
798 info.propName = "S_THERMOMETER_ONEWIRE_MOTOR";
799 info.label = "Slave motor temperature";
800 info.format = "%3.2f";
801 info.minValue = -100;
802 info.maxValue = 100;
803 break;
804 case 20:
805 info.propName = "S_THERMOMETER_ONEWIRE_OUTSIDE";
806 info.label = "Slave outside temperature";
807 info.format = "%3.2f";
808 info.minValue = -100;
809 info.maxValue = 100;
810 break;
811 case 21:
812 info.propName = "S_THERMOMETER_ONEWIRE_MIRROR_1";
813 info.label = "Slave mirror 1 temperature";
814 info.format = "%3.2f";
815 info.minValue = -100;
816 info.maxValue = 100;
817 break;
818 case 22:
819 info.propName = "S_THERMOMETER_ONEWIRE_MIRROR_2";
820 info.label = "Slave mirror 2 temperature";
821 info.format = "%3.2f";
822 info.minValue = -100;
823 info.maxValue = 100;
824 break;
825 case 23:
826 info.propName = "S_HIGROMETER_TEMPERATURE";
827 info.label = "Slave higrometer temperature";
828 info.format = "%3.2f";
829 info.minValue = -100;
830 info.maxValue = 100;
831 break;
832 case 24:
833 info.propName = "S_PIROMETER_AMBIENT";
834 info.label = "Slave pirometer ambient temperature";
835 info.format = "%3.2f";
836 info.minValue = -100;
837 info.maxValue = 100;
838 break;
839 case 25:
840 info.propName = "S_PIROMETER_SENSOR";
841 info.label = "Slave pirometer sensor temperature";
842 info.format = "%3.2f";
843 info.minValue = -100;
844 info.maxValue = 100;
845 break;
846 case 26:
847 info.propName = "S_BAROMETER_PRESSURE";
848 info.label = "Slave barometer pressure";
849 info.format = "%4.2f";
850 info.minValue = 0;
851 info.maxValue = 2000;
852 break;
853 case 27:
854 info.propName = "S_HIGROMETER_HUMIDITY";
855 info.label = "Slave higrometer humidity";
856 info.format = "%3.2f";
857 info.minValue = 0;
858 info.maxValue = 100;
859 break;
860 default:
861 LOG_ERROR("invalid sensor index");
862 break;
863 }
864 return info;
865}
866
868{
869 return sensors[index];
870}
871
873{
874 return 6;
875}
876
878{
880 switch(index)
881 {
882 case 0:
883 info.propName = "RELAY_1";
884 info.label = "Relay 1";
885 break;
886 case 1:
887 info.propName = "RELAY_2";
888 info.label = "Relay 2";
889 break;
890 case 2:
891 info.propName = "RELAY_3";
892 info.label = "Relay 3";
893 break;
894 case 3:
895 info.propName = "S_RELAY_1";
896 info.label = "Slave relay 1";
897 break;
898 case 4:
899 info.propName = "S_RELAY_2";
900 info.label = "Slave relay 2";
901 break;
902 case 5:
903 info.propName = "S_RELAY_3";
904 info.label = "Slave relay 3";
905 break;
906 default:
907 LOG_ERROR("invalid relay index");
908 break;
909 }
910 return info;
911}
912
914{
915 return relays[index] ? ISS_ON : ISS_OFF;
916}
917
919{
920 std::string res;
921 std::string cmd;
922 if(index >= 3)
923 {
924 cmd = "slave=";
925 index -= 3;
926 }
927 if(state == ISS_ON)
928 {
929 cmd += "switchOnFreeRelay=";
930 }
931 else
932 {
933 cmd += "switchOffFreeRelay=";
934 }
935 cmd += std::to_string(index + 1);
936 performCommand(cmd, res);
937}
938
940{
941 return 16;
942}
943
945{
947 switch(index)
948 {
949 case 0:
950 info.propName = "DETECT_230LOSS";
951 info.label = "Detect 230V loss";
952 break;
953 case 1:
954 info.propName = "ENCODERA";
955 info.label = "Rotary encoder";
956 break;
957 case 2:
958 info.propName = "HOMESENSOR";
959 info.label = "Home sensor";
960 break;
961 case 3:
962 info.propName = "FREE1";
963 info.label = "Free 1";
964 break;
965 case 4:
966 info.propName = "FREE2";
967 info.label = "Free 2";
968 break;
969 case 5:
970 info.propName = "RAINSENSOR";
971 info.label = "Rain sensor";
972 break;
973 case 6:
974 info.propName = "CLOUDSENSOR";
975 info.label = "Cloud sensor";
976 break;
977 case 7:
978 info.propName = "TELESCOPE_A_H";
979 info.label = "Telescope at home";
980 break;
981 case 8:
982 info.propName = "S_DETECT_230LOSS";
983 info.label = "Slave detect 230V loss";
984 break;
985 case 9:
986 info.propName = "S_ENCODERA";
987 info.label = "Shutter encoder";
988 break;
989 case 10:
990 info.propName = "S_HOMESENSOR";
991 info.label = "Slave home sensor";
992 break;
993 case 11:
994 info.propName = "OPEN1";
995 info.label = "Shutter 1 open";
996 break;
997 case 12:
998 info.propName = "CLOSED1";
999 info.label = "Shutter 1 closed";
1000 break;
1001 case 13:
1002 info.propName = "S_RAINSENSOR";
1003 info.label = "Slave rain sensor";
1004 break;
1005 case 14:
1006 info.propName = "S_CLOUDSENSOR";
1007 info.label = "Slave cloud sensor";
1008 break;
1009 case 15:
1010 info.propName = "S_TELESCOPE_A_H";
1011 info.label = "Slave telescope at home";
1012 break;
1013 default:
1014 LOG_ERROR("invalid input index");
1015 break;
1016 }
1017 return info;
1018}
1019
1021{
1022 return inputs[index] ? ISS_ON : ISS_OFF;
1023}
1024
1026{
1027 std::string res;
1028 std::string cmd = "setHomeSignalLow=";
1029
1030 switch(polarity)
1031 {
1032 case ACTIVE_HIGH:
1033 cmd += "0";
1034 break;
1035 case ACTIVE_LOW:
1036 cmd += "1";
1037 break;
1038 }
1039 performCommand(cmd, res);
1040}
1041
1042std::vector<std::string> ScopeDomeArduino::splitString(const std::string &src, char splitChar)
1043{
1044 std::vector<std::string> results;
1045
1046 size_t start = 0;
1047 size_t end;
1048 while( (end = src.find(splitChar, start)) != std::string::npos)
1049 {
1050 results.push_back(src.substr(start, end - start));
1051 start = end + 1;
1052 }
1053 results.push_back(src.substr(start, std::string::npos));
1054 return results;
1055}
The Interface class is the base class for all INDI connection plugins.
virtual Type type()
type Return connection type
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
The TCP class manages connection with devices over the network via TCP/IP. Upon successful connection...
virtual SensorInfo getSensorInfo(size_t index) override
virtual void controlShutter(ShutterOperation operation) override
virtual size_t getNumberOfRelays() override
virtual void setHomeSensorPolarity(HomeSensorPolarity polarity) override
virtual ISState getInputValue(size_t index) override
ScopeDomeArduino(ScopeDome *driver, Connection::Interface *interface)
virtual int getRotationCounterExt() override
virtual uint32_t getStatus() override
virtual void resetCounter() override
virtual size_t getNumberOfSensors() override
virtual uint32_t getStepsPerRevolution() override
virtual void getFirmwareVersions(double &main, double &rotary) override
virtual bool isCalibrationNeeded() override
virtual bool detect() override
virtual void abort() override
virtual double getSensorValue(size_t index) override
virtual size_t getNumberOfInputs() override
virtual RelayInfo getRelayInfo(size_t index) override
virtual ISState getInputState(AbstractInput input) override
virtual int getRotationCounter() override
virtual void calibrate() override
virtual ISState getRelayState(size_t index) override
virtual void findHome() override
virtual void move(int steps) override
virtual void setRelayState(size_t index, ISState state) override
virtual int updateState() override
virtual int setOutputState(AbstractOutput output, ISState state) override
virtual InputInfo getInputInfo(size_t index) override
int main()
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
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 MAXRBUF
Definition indidriver.c:52
#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::vector< std::string > split(const std::string &input, const std::string &regex)
uint8_t cmd[4]
Definition pwc-ioctl.h:2
#define SCOPEDOME_TIMEOUT