Instrument Neutral Distributed Interface INDI 2.2.5
scopedome_usb21.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_usb21.h"
26#include "indicom.h"
27
28#include <termios.h>
29#include <unistd.h>
30#include <vector>
31
32#define SCOPEDOME_TIMEOUT 2
33
34static const uint8_t header = 0xaa;
35
36const char* ScopeDomeUSB21::cmdToString(Command cmd) const
37{
38 static const CmdStr cmdStrMap[] =
39 {
40 { ACK_c, "ACK_c" },
41 { FunctionNotSupported, "FunctionNotSupported" },
42 { MotionConflict, "MotionConflict" },
43 { ParamError, "ParamError" },
44 { FuncBufferError, "FuncBufferError" },
45 { ConnectionTest, "ConnectionTest" },
46 { SetAllDigital, "SetAllDigital" },
47 { ClearDigitalChannel, "ClearDigitalChannel" },
48 { ClearAllDigital, "ClearAllDigital" },
49 { SetDigitalChannel, "SetDigitalChannel" },
50 { GetDigitalChannel, "GetDigitalChannel" },
51 { GetAllDigital, "GetAllDigital" },
52
53 { GetCounter, "GetCounter" },
54 { ResetCounter, "ResetCounter" },
55 { SetCounterDebounceTime, "SetCounterDebounceTime" },
56 { SetCounterMax, "SetCounterMax" },
57 { GetCounterMax, "GetCounterMax" },
58 { SetCounterMin, "SetCounterMin" },
59 { GetCounterMin, "GetCounterMin" },
60 { CCWRotation, "CCWRotation" },
61 { CWRotation, "CWRotation" },
62
63 { GetAnalogChannel, "GetAnalogChannel" },
64 { OutputAnalogChannel1, "OutputAnalogChannel1" },
65 { OutputAnalogChannel2, "OutputAnalogChannel2" },
66 { OutputAllAnalog, "OutputAllAnalog" },
67 { ClearAnalogChannel, "ClearAnalogChannel" },
68 { SetAllAnalog, "SetAllAnalog" },
69 { ClearAllAnalog, "ClearAllAnalog" },
70 { SetAnalogChannel, "SetAnalogChannel" },
71 { GetVersionFirmware, "GetVersionFirmware" },
72
73 { SetAllRelays, "SetAllRelays" },
74 { ClearRelay, "ClearRelay" },
75 { SetRelay, "SetRelay" },
76
77 { GetStatus, "GetStatus" },
78 { GetTemp1, "GetTemp1" },
79 { GetTemp2, "GetTemp2" },
80 { GetTemp3, "GetTemp3" },
81 { GetTemp4, "GetTemp4" },
82 { GetTemp5, "GetTemp5" },
83 { GetDscnt, "GetDscnt" },
84 { GetHum, "GetHum" },
85 { GetTempHum, "GetTempHum" },
86 { GetAnalog1, "GetAnalog1" },
87 { GetAnalog2, "GetAnalog2" },
88 { Get230, "Get230" },
89 { EnableAutoClose, "EnableAutoClose" },
90 { DisableAutoClose, "DisableAutoClose" },
91 { GetAutoClose, "GetAutoClose" },
92
93 { EnablePosSave, "EnablePosSave" },
94 { DisablePosSave, "DisablePosSave" },
95 { GetPosSave, "GetPosSave" },
96
97 { GetCounterExt, "GetCounterExt" },
98 { ResetCounterExt, "ResetCounterExt" },
99 { SetCounterDebounceTimeExt, "SetCounterDebounceTimeExt" },
100 { SetCounterMaxExt, "SetCounterMaxExt" },
101 { GetCounterMaxExt, "GetCounterMaxExt" },
102
103 { SetCounterMinExt, "SetCounterMinExt" },
104 { GetCounterMinExt, "GetCounterMinExt" },
105
106 { GetAllDigitalExt, "GetAllDigitalExt" },
107 { StandbyOff, "StandbyOff" },
108 { StandbyOn, "StandbyOn" },
109 { GetPowerState, "GetPowerState" },
110 { SetImpPerTurn, "SetImpPerTurn" },
111
112 { UpdateFirmware, "UpdateFirmware" },
113 { UpdateRotaryFirmwareSerial, "UpdateRotaryFirmwareSerial" },
114 { UpdateRotaryFirmwareRf, "UpdateRotaryFirmwareRf" },
115
116 { GoHome, "GoHome" },
117
118 { GetMainAnalog1, "GetMainAnalog1" },
119 { GetMainAnalog2, "GetMainAnalog2" },
120
121 { GetPressure, "GetPressure" },
122 { GetTempIn, "GetTempIn" },
123 { GetTempOut, "GetTempOut" },
124
125 { GetRotaryCounter1, "GetRotaryCounter1" },
126 { GetRotaryCounter2, "GetRotaryCounter2" },
127 { ResetRotaryCounter1, "ResetRotaryCounter1" },
128 { ResetRotaryCounter2, "ResetRotaryCounter2" },
129
130 { RotaryAutoOpen1, "RotaryAutoOpen1" },
131 { RotaryAutoOpen2, "RotaryAutoOpen2" },
132
133 { RotaryAutoClose1, "RotaryAutoClose1" },
134 { RotaryAutoClose2, "RotaryAutoClose2" },
135
136 { GetLinkStrength, "GetLinkStrength" },
137
138 { GetLowVoltageMain, "GetLowVoltageMain" },
139 { SetLowVoltageMain, "SetLowVoltageMain" },
140 { GetLowVoltageRotary, "GetLowVoltageRotary" },
141 { SetLowVoltageRotary, "SetLowVoltageRotary" },
142
143 { GetHomeSensorPosition, "GetHomeSensorPosition" },
144 { SetHomeSensorPosition, "SetHomeSensorPosition" },
145
146 { GetImpPerTurn, "GetImpPerTurn" },
147 { Stop, "Stop" },
148
149 { GetStartCnt, "GetStartCnt" },
150 { Ready, "Ready" },
151
152 { SetStopTime, "SetStopTime" },
153 { GetStopTime, "GetStopTime" },
154
155 { GetCounterDebounceTimeExt, "GetCounterDebounceTimeExt" },
156
157 { SetDebounceTimeInputs, "SetDebounceTimeInputs" },
158 { GetDebounceTimeInputs, "GetDebounceTimeInputs" },
159
160 { FindHome, "FindHome" },
161 { NegHomeSensorActiveState, "NegHomeSensorActiveState" },
162
163 // { PowerOnlyAtHome, "PowerOnlyAtHome" },
164
165 { SetAutoCloseEvents, "SetAutoCloseEvents" },
166 { GetAutoCloseEvents, "GetAutoCloseEvents" },
167 { SetAutoCloseTime, "SetAutoCloseTime" },
168 { GetAutoCloseTime, "GetAutoCloseTime" },
169
170 { SetShutterConfig, "SetShutterConfig" },
171 { GetShutterConfig, "GetShutterConfig" },
172
173 { GetVersionFirmwareRotary, "GetVersionFirmwareRotary" },
174 { GetCommunicationMode, "GetCommunicationMode" },
175 { SetCommunicationMode, "SetCommunicationMode" },
176
177 { SetTherm1Mode, "SetTherm1Mode" },
178 { SetTherm1Out1, "SetTherm1Out1" },
179 { SetTherm1Out2, "SetTherm1Out2" },
180 { SetTherm1Hist, "SetTherm1Hist" },
181 { SetTherm1VAL, "SetTherm1VAL" },
182
183 { GetTherm1Mode, "GetTherm1Mode" },
184 { GetTherm1Out1, "GetTherm1Out1" },
185 { GetTherm1Out2, "GetTherm1Out2" },
186 { GetTherm1Hist, "GetTherm1Hist" },
187 { GetTherm1VAL, "GetTherm1VAL" },
188
189 { SetTherm2Mode, "SetTherm2Mode" },
190 { SetTherm2Out1, "SetTherm2Out1" },
191 { SetTherm2Out2, "SetTherm2Out2" },
192 { SetTherm2Hist, "SetTherm2Hist" },
193 { SetTherm2VAL, "SetTherm2VAL" },
194
195 { GetTherm2Mode, "GetTherm2Mode" },
196 { GetTherm2Out1, "GetTherm2Out1" },
197 { GetTherm2Out2, "GetTherm2Out2" },
198 { GetTherm2Hist, "GetTherm2Hist" },
199 { GetTherm2VAL, "GetTherm2VAL" },
200
201 { SetTherm3Mode, "SetTherm3Mode" },
202 { SetTherm3Out1, "SetTherm3Out1" },
203 { SetTherm3Out2, "SetTherm3Out2" },
204 { SetTherm3Hist, "SetTherm3Hist" },
205 { SetTherm3VAL, "SetTherm3VAL" },
206
207 { GetTherm3Mode, "GetTherm3Mode" },
208 { GetTherm3Out1, "GetTherm3Out1" },
209 { GetTherm3Out2, "GetTherm3Out2" },
210 { GetTherm3Hist, "GetTherm3Hist" },
211 { GetTherm3VAL, "GetTherm3VAL" },
212 { StartSafeCommunication, "StartSafeCommunication" },
213 { StopSafeCommunication, "StopSafeCommunication" },
214 { SetAutoCloseOrder, "SetAutoCloseOrder" },
215 { GetAutoCloseOrder, "GetAutoCloseOrder" },
216
217 { FullSystemCal, "FullSystemCal" },
218 { IsFullSystemCalReq, "IsFullSystemCalReq" }
219 };
220
221 for (auto i = 0u; i < sizeof(cmdStrMap) / sizeof(CmdStr); ++i)
222 {
223 if (cmdStrMap[i].cmd == cmd)
224 {
225 return cmdStrMap[i].str;
226 }
227 }
228 return "Unknown command";
229}
230
232{
233 int rc = -1;
234 Command cmd;
235 LOGF_DEBUG("Detect! %d", rc);
236 rc = write(ConnectionTest);
237 LOGF_DEBUG("write rc: %d", rc);
238 rc = read(cmd);
239 LOGF_DEBUG("read rc: %d, cmd %s (%d)", rc, cmdToString(cmd), (int)cmd);
240
241 if (cmd != ConnectionTest)
242 {
243 return false;
244 }
245 // Disable "safe" communication mode that resets connection after few seconds
246 rc = write(StopSafeCommunication);
247 rc = read(cmd);
248 return (cmd == StopSafeCommunication);
249}
250
251uint8_t ScopeDomeUSB21::CRC(uint8_t crc, uint8_t data)
252{
253 crc ^= data;
254
255 for (int i = 0; i < 8; i++)
256 {
257 if (crc & 1)
258 crc = ((crc >> 1) ^ 0x8C);
259 else
260 crc >>= 1;
261 }
262 return crc;
263}
264
265int ScopeDomeUSB21::writeBuf(Command cmd, uint8_t len, uint8_t *buff)
266{
267 int BytesToWrite = len + 4;
268 int nbytes_written = 0, rc = -1;
269 char errstr[MAXRBUF];
270
271 std::vector<uint8_t> cbuf(BytesToWrite, 0);
272 cbuf[0] = header;
273 cbuf[3] = CRC(0, cbuf[0]);
274 cbuf[1] = len;
275 cbuf[3] = CRC(cbuf[3], cbuf[1]);
276 cbuf[2] = cmd;
277 cbuf[3] = CRC(cbuf[3], cbuf[2]);
278
279 for (int i = 0; i < len; i++)
280 {
281 cbuf[i + 4] = buff[i];
282 cbuf[3] = CRC(cbuf[3], buff[i]);
283 }
284
285 tcflush(PortFD, TCIOFLUSH);
286
287 prevcmd = cmd;
288
289 // Write buffer
290 LOGF_DEBUG("write buf: %x %x %x %x %x", cbuf[0], cbuf[1], cbuf[2], cbuf[3], cbuf[4]);
291 if ((rc = tty_write(PortFD, (const char *)cbuf.data(), cbuf.size() * sizeof(cbuf[0]), &nbytes_written)) != TTY_OK)
292 {
293 tty_error_msg(rc, errstr, MAXRBUF);
294 LOGF_ERROR("Error writing command: %s. Cmd %s (%d)", errstr, cmdToString(cmd), cmd);
295 }
296 return rc;
297}
298
299int ScopeDomeUSB21::write(Command cmd)
300{
301 int nbytes_written = 0, rc = -1;
302 uint8_t cbuf[4];
303 char errstr[MAXRBUF];
304
305 tcflush(PortFD, TCIOFLUSH);
306
307 cbuf[0] = header;
308 cbuf[3] = CRC(0, cbuf[0]);
309 cbuf[1] = 0;
310 cbuf[3] = CRC(cbuf[3], cbuf[1]);
311 cbuf[2] = cmd;
312 cbuf[3] = CRC(cbuf[3], cbuf[2]);
313
314 prevcmd = cmd;
315
316 // Write buffer
317 LOGF_DEBUG("write cmd: %x %x %x %x", cbuf[0], cbuf[1], cbuf[2], cbuf[3]);
318 if ((rc = tty_write(PortFD, (const char *)cbuf, sizeof(cbuf), &nbytes_written)) != TTY_OK)
319 {
320 tty_error_msg(rc, errstr, MAXRBUF);
321 LOGF_ERROR("Error writing command: %s. Cmd: %s (%d)", errstr, cmdToString(cmd), cmd);
322 }
323 return rc;
324}
325
326int ScopeDomeUSB21::readBuf(Command &cmd, uint8_t len, uint8_t *buff)
327{
328 int nbytes_read = 0, rc = -1;
329 int BytesToRead = len + 4;
330 std::vector<uint8_t> cbuf(BytesToRead, 0);
331 char errstr[MAXRBUF];
332
333 // Read buffer
334 if ((rc = tty_read(PortFD, (char *)cbuf.data(), cbuf.size() * sizeof(cbuf[0]), SCOPEDOME_TIMEOUT, &nbytes_read)) != TTY_OK)
335 {
336 tty_error_msg(rc, errstr, MAXRBUF);
337 LOGF_ERROR("Error reading: %s. Cmd: %s (%d)", errstr, cmdToString(prevcmd), prevcmd);
338 return rc;
339 }
340
341 LOGF_DEBUG("readbuf cmd: %x %x %x %x", cbuf[0], cbuf[1], cbuf[2], cbuf[3]);
342 uint8_t Checksum = CRC(0, cbuf[0]);
343 Checksum = CRC(Checksum, cbuf[1]);
344 cmd = (Command)cbuf[2];
345 Checksum = CRC(Checksum, cbuf[2]);
346
347 for (int i = 0; i < len; i++)
348 {
349 buff[i] = cbuf[i + 4];
350 Checksum = CRC(Checksum, cbuf[i + 4]);
351 }
352
353 if (cbuf[3] != Checksum)
354 {
355 LOGF_ERROR("readbuf checksum error, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
356 return CHECKSUM_ERROR;
357 }
358 if (cmd == FunctionNotSupported)
359 {
360 LOGF_ERROR("readbuf not supported error, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
361 return FUNCTION_NOT_SUPPORTED_BY_FIRMWARE;
362 }
363
364 if (cbuf[1] != len)
365 {
366 LOGF_ERROR("readbuf packet length error, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
367 return PACKET_LENGTH_ERROR;
368 }
369 return rc;
370}
371
372int ScopeDomeUSB21::read(Command &cmd)
373{
374 int nbytes_read = 0, rc = -1;
375 int err = 0;
376 uint8_t cbuf[4] = { 0 };
377 char errstr[MAXRBUF];
378
379 // Read buffer
380 if ((rc = tty_read(PortFD, (char *)cbuf, sizeof(cbuf), SCOPEDOME_TIMEOUT, &nbytes_read)) != TTY_OK)
381 {
382 tty_error_msg(rc, errstr, MAXRBUF);
383 LOGF_ERROR("Error reading: %s. Cmd %s (%d)", errstr, cmdToString(prevcmd), prevcmd);
384 return rc;
385 }
386
387 LOGF_DEBUG("read cmd: %x %x %x %x", cbuf[0], cbuf[1], cbuf[2], cbuf[3]);
388 uint8_t Checksum = CRC(0, cbuf[0]);
389 Checksum = CRC(Checksum, cbuf[1]);
390 cmd = (Command)cbuf[2];
391 Checksum = CRC(Checksum, cbuf[2]);
392
393 if (cbuf[3] != Checksum || cbuf[1] != 0)
394 {
395 LOGF_ERROR("read checksum error, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
396 return CHECKSUM_ERROR;
397 }
398 switch (cmd)
399 {
400 case MotionConflict:
401 LOGF_ERROR("read motion conflict, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
402 err = MOTION_CONFLICT;
403 break;
404
405 case FunctionNotSupported:
406 LOGF_ERROR("read function not supported, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
407 err = FUNCTION_NOT_SUPPORTED;
408 break;
409
410 case ParamError:
411 LOGF_ERROR("read param error, cmd: %s (%d)", cmdToString(prevcmd), prevcmd);
412 err = PARAM_ERROR;
413 break;
414 default:
415 break;
416 }
417 return err;
418}
419
420/************************************************************************************
421 *
422 * ***********************************************************************************/
423bool ScopeDomeUSB21::readFloat(Command cmd, float &dst)
424{
425 float value;
426 Command c;
427 int rc;
428 int retryCount = 2;
429 do
430 {
431 rc = write(cmd);
432 if (rc == 0)
433 rc = readBuf(c, 4, (uint8_t *)&value);
434 else
435 reconnect();
436 }
437 while (rc != 0 && --retryCount);
438 LOGF_DEBUG("readFloat: %s (%d) = %f", cmdToString(cmd), cmd, value);
439 if (rc == 0)
440 {
441 dst = value;
442 return true;
443 }
444 return false;
445}
446
447bool ScopeDomeUSB21::readU8(Command cmd, uint8_t &dst)
448{
449 uint8_t value;
450 Command c;
451 int rc;
452 int retryCount = 2;
453 do
454 {
455 rc = write(cmd);
456 if (rc == 0)
457 rc = readBuf(c, 1, &value);
458 else
459 reconnect();
460 }
461 while (rc != 0 && --retryCount);
462 LOGF_DEBUG("readU8: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
463 if (rc == 0)
464 {
465 dst = value;
466 return true;
467 }
468 return false;
469}
470
471bool ScopeDomeUSB21::readS8(Command cmd, int8_t &dst)
472{
473 int8_t value;
474 Command c;
475 int rc;
476 int retryCount = 2;
477 do
478 {
479 rc = write(cmd);
480 if (rc == 0)
481 rc = readBuf(c, 1, (uint8_t *)&value);
482 else
483 reconnect();
484 }
485 while (rc != 0 && --retryCount);
486 LOGF_DEBUG("readS8: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
487 if (rc == 0)
488 {
489 dst = value;
490 return true;
491 }
492 return false;
493}
494
495bool ScopeDomeUSB21::readU16(Command cmd, uint16_t &dst)
496{
497 uint16_t value;
498 Command c;
499 int rc;
500 int retryCount = 2;
501 do
502 {
503 rc = write(cmd);
504 if (rc == 0)
505 rc = readBuf(c, 2, (uint8_t *)&value);
506 else
507 reconnect();
508 }
509 while (rc != 0 && --retryCount);
510 LOGF_DEBUG("readU16: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
511 if (rc == 0)
512 {
513 dst = value;
514 return true;
515 }
516 return false;
517}
518
519bool ScopeDomeUSB21::readS16(Command cmd, int16_t &dst)
520{
521 int16_t value;
522 Command c;
523 int rc;
524 int retryCount = 2;
525 do
526 {
527 rc = write(cmd);
528 if (rc == 0)
529 rc = readBuf(c, 2, (uint8_t *)&value);
530 else
531 reconnect();
532 }
533 while (rc != 0 && --retryCount);
534 LOGF_DEBUG("readS16: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
535 if (rc == 0)
536 {
537 dst = value;
538 return true;
539 }
540 return false;
541}
542
543bool ScopeDomeUSB21::readU32(Command cmd, uint32_t &dst)
544{
545 uint32_t value;
546 Command c;
547 int rc;
548 int retryCount = 2;
549 do
550 {
551 rc = write(cmd);
552 if (rc == 0)
553 rc = readBuf(c, 4, (uint8_t *)&value);
554 else
555 reconnect();
556 }
557 while (rc != 0 && --retryCount);
558 LOGF_DEBUG("readU32: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
559 if (rc == 0)
560 {
561 dst = value;
562 return true;
563 }
564 return false;
565}
566
567bool ScopeDomeUSB21::readS32(Command cmd, int32_t &dst)
568{
569 int32_t value;
570 Command c;
571 int rc;
572 int retryCount = 2;
573 do
574 {
575 rc = write(cmd);
576 if (rc == 0)
577 rc = readBuf(c, 4, (uint8_t *)&value);
578 else
579 reconnect();
580 }
581 while (rc != 0 && --retryCount);
582 LOGF_DEBUG("readS32: %s (%d) = 0x%x", cmdToString(cmd), cmd, value);
583 if (rc == 0)
584 {
585 dst = value;
586 return true;
587 }
588 return false;
589}
590
591int ScopeDomeUSB21::readBuffer(Command cmd, int len, uint8_t *cbuf)
592{
593 int rc;
594 int retryCount = 2;
595 Command c;
596 do
597 {
598 rc = write(cmd);
599 if (rc == 0)
600 rc = readBuf(c, len, cbuf);
601 else
602 reconnect();
603 }
604 while (rc != 0 && --retryCount);
605 return rc;
606}
607
608int ScopeDomeUSB21::writeCmd(Command cmd)
609{
610 int rc = write(cmd);
611 if (rc != 0)
612 {
613 reconnect();
614 return rc;
615 }
616 return read(cmd);
617}
618
619int ScopeDomeUSB21::writeU8(Command cmd, uint8_t value)
620{
621 int rc = writeBuf(cmd, 1, &value);
622 if (rc != 0)
623 {
624 reconnect();
625 return rc;
626 }
627 return read(cmd);
628}
629
630int ScopeDomeUSB21::writeU16(Command cmd, uint16_t value)
631{
632 int rc = writeBuf(cmd, 2, (uint8_t *)&value);
633 if (rc != 0)
634 {
635 reconnect();
636 return rc;
637 }
638 return read(cmd);
639}
640
641int ScopeDomeUSB21::writeU32(Command cmd, uint32_t value)
642{
643 int rc = writeBuf(cmd, 4, (uint8_t *)&value);
644 if (rc != 0)
645 {
646 reconnect();
647 return rc;
648 }
649 return read(cmd);
650}
651
652int ScopeDomeUSB21::writeBuffer(Command cmd, int len, uint8_t *cbuf)
653{
654 int rc = writeBuf(cmd, len, cbuf);
655 if (rc != 0)
656 {
657 reconnect();
658 return rc;
659 }
660 return read(cmd);
661}
662
663void ScopeDomeUSB21::reconnect()
664{
665 parent->reconnect();
666}
667
669{
670 int rc = readU16(GetStatus, status);
671 rc |= readS16(GetCounter, counter);
672 rc |= readBuffer(GetAllDigitalExt, 5, digitalSensorState);
673 return rc;
674}
675
677{
678 return status;
679}
680
681void ScopeDomeUSB21::getFirmwareVersions(double &main, double &rotary)
682{
683 uint16_t fwVersion = 0;
684 readU16(GetVersionFirmware, fwVersion);
685 main = fwVersion / 100.0;
686
687 uint8_t fwVersionRotary = 0;
688 readU8(GetVersionFirmwareRotary, fwVersionRotary);
689 rotary = (fwVersionRotary + 9) / 10.0;
690}
691
693{
694 uint32_t stepsPerRevolution = 0;
695 readU32(GetImpPerTurn, stepsPerRevolution);
696 return stepsPerRevolution;
697}
698
699// Abstract versions
701{
702 DigitalIO channel;
703 switch(input)
704 {
705 case HOME:
706 channel = IN_HOME;
707 break;
708 case OPEN1:
709 channel = IN_OPEN1;
710 break;
711 case CLOSED1:
712 channel = IN_CLOSED1;
713 break;
714 case OPEN2:
715 channel = IN_OPEN2;
716 break;
717 case CLOSED2:
718 channel = IN_CLOSED1;
719 break;
720 case ROTARY_LINK:
721 channel = IN_ROT_LINK;
722 break;
723 default:
724 LOG_ERROR("invalid input");
725 return ISS_OFF;
726 }
727 return getInputState(channel);
728}
729
731{
732 DigitalIO channel;
733 switch(output)
734 {
735 case RESET:
736 channel = OUT_RELAY1;
737 break;
738 case CW:
739 channel = OUT_CW;
740 break;
741 case CCW:
742 channel = OUT_CCW;
743 break;
744 default:
745 LOG_ERROR("invalid output");
746 return ISS_OFF;
747 }
748 return setOutputState(channel, onOff);
749}
750
751// Internal versions
752ISState ScopeDomeUSB21::getInputState(DigitalIO channel)
753{
754 int ch = (int)channel;
755 int byte = ch >> 3;
756 uint8_t bit = 1 << (ch & 7);
757 return (digitalSensorState[byte] & bit) ? ISS_ON : ISS_OFF;
758}
759
760int ScopeDomeUSB21::setOutputState(DigitalIO channel, ISState onOff)
761{
762 return writeU8(onOff == ISS_ON ? SetDigitalChannel : ClearDigitalChannel, (uint8_t)channel);
763}
764
766{
767 return counter;
768}
769
771{
772 readS32(GetCounterExt, counterExt);
773 return counterExt;
774}
775
777{
778 uint8_t calibrationNeeded = false;
779 readU8(IsFullSystemCalReq, calibrationNeeded);
780 return calibrationNeeded != 0;
781}
782
784{
785 writeCmd(Stop);
786}
787
789{
790 writeCmd(FullSystemCal);
791}
792
794{
795 writeCmd(FindHome);
796}
797
799{
800 switch(operation)
801 {
802 case OPEN_SHUTTER:
803 setOutputState(OUT_CLOSE1, ISS_OFF);
804 setOutputState(OUT_OPEN1, ISS_ON);
805 break;
806 case CLOSE_SHUTTER:
807 setOutputState(OUT_CLOSE1, ISS_ON);
808 setOutputState(OUT_OPEN1, ISS_OFF);
809 break;
810 case STOP_SHUTTER:
811 setOutputState(OUT_CLOSE1, ISS_OFF);
812 setOutputState(OUT_OPEN1, ISS_OFF);
813 break;
814 }
815}
816
818{
819 writeCmd(ResetCounter);
820 writeCmd(ResetCounterExt);
821}
822
823void ScopeDomeUSB21::move(int steps)
824{
825 if(steps < 0)
826 {
827 writeU16(CCWRotation, -steps);
828 }
829 else
830 {
831 writeU16(CWRotation, steps);
832 }
833}
834
836{
837 return 11;
838}
839
841{
843 switch(index)
844 {
845 case 0:
846 info.propName = "LINK_STRENGTH";
847 info.label = "Shutter link strength";
848 info.format = "%3.0f";
849 info.minValue = 0;
850 info.maxValue = 100;
851 break;
852 case 1:
853 info.propName = "SHUTTER_POWER";
854 info.label = "Shutter internal power";
855 info.format = "%2.2f";
856 info.minValue = 0;
857 info.maxValue = 100;
858 break;
859 case 2:
860 info.propName = "SHUTTER_BATTERY";
861 info.label = "Shutter battery power";
862 info.format = "%2.2f";
863 info.minValue = 0;
864 info.maxValue = 100;
865 break;
866 case 3:
867 info.propName = "CARD_POWER";
868 info.label = "Card internal power";
869 info.format = "%2.2f";
870 info.minValue = 0;
871 info.maxValue = 100;
872 break;
873 case 4:
874 info.propName = "CARD_BATTERY";
875 info.label = "Card battery power";
876 info.format = "%2.2f";
877 info.minValue = 0;
878 info.maxValue = 100;
879 break;
880 case 5:
881 info.propName = "TEMP_DOME_IN";
882 info.label = "Temperature in dome";
883 info.format = "%2.2f";
884 info.minValue = -100;
885 info.maxValue = 100;
886 break;
887 case 6:
888 info.propName = "TEMP_DOME_OUT";
889 info.label = "Temperature outside dome";
890 info.format = "%2.2f";
891 info.minValue = -100;
892 info.maxValue = 100;
893 break;
894 case 7:
895 info.propName = "TEMP_DOME_HUMIDITY";
896 info.label = "Temperature humidity sensor";
897 info.format = "%2.2f";
898 info.minValue = -100;
899 info.maxValue = 100;
900 break;
901 case 8:
902 info.propName = "HUMIDITY";
903 info.label = "Humidity";
904 info.format = "%3.2f";
905 info.minValue = 0;
906 info.maxValue = 100;
907 break;
908 case 9:
909 info.propName = "PRESSURE";
910 info.label = "Pressure";
911 info.format = "%4.1f";
912 info.minValue = 0;
913 info.maxValue = 2000;
914 break;
915 case 10:
916 info.propName = "DEW_POINT";
917 info.label = "Dew point";
918 info.format = "%2.2f";
919 info.minValue = -100;
920 info.maxValue = 100;
921 break;
922 default:
923 LOG_ERROR("invalid sensor index");
924 break;
925 }
926 return info;
927}
928
930{
931 double value = 0;
932
933 switch(index)
934 {
935 case 0:
936 {
937 readU8(GetLinkStrength, linkStrength);
938 value = linkStrength;
939
940 // My shutter unit occasionally disconnects so implement a simple watchdog
941 // to check for link strength and reset the controller if link is lost for
942 // more than 5 polling cycles
943 static int count = 0;
944 if (linkStrength == 0)
945 {
946 if (++count > 5)
947 {
948 // Issue reset
950 count = 0;
951 }
952 }
953 else
954 {
955 count = 0;
956 }
957 break;
958 }
959 case 1:
960 readFloat(GetAnalog1, sensors[0]);
961 value = sensors[0];
962 break;
963 case 2:
964 readFloat(GetAnalog2, sensors[1]);
965 value = sensors[1];
966 break;
967 case 3:
968 readFloat(GetMainAnalog1, sensors[2]);
969 value = sensors[2];
970 break;
971 case 4:
972 readFloat(GetMainAnalog2, sensors[3]);
973 value = sensors[3];
974 break;
975 case 5:
976 readFloat(GetTempIn, sensors[4]);
977 value = sensors[4];
978 break;
979 case 6:
980 readFloat(GetTempOut, sensors[5]);
981 value = sensors[5];
982 break;
983 case 7:
984 readFloat(GetTempHum, sensors[6]);
985 value = sensors[6];
986 break;
987 case 8:
988 readFloat(GetHum, sensors[7]);
989 value = sensors[7];
990 break;
991 case 9:
992 readFloat(GetPressure, sensors[8]);
993 value = sensors[8];
994 break;
995 case 10:
996 value = parent->getDewPoint(sensors[7], sensors[6]);
997 break;
998 default:
999 LOG_ERROR("invalid sensor index");
1000 break;
1001 }
1002 return value;
1003}
1004
1006{
1007 return 8;
1008}
1009
1011{
1013 switch(index)
1014 {
1015 case 0:
1016 info.propName = "CCD";
1017 info.label = "CCD";
1018 break;
1019 case 1:
1020 info.propName = "SCOPE";
1021 info.label = "Telescope";
1022 break;
1023 case 2:
1024 info.propName = "LIGHT";
1025 info.label = "Light";
1026 break;
1027 case 3:
1028 info.propName = "FAN";
1029 info.label = "Fan";
1030 break;
1031 case 4:
1032 info.propName = "RELAY_1";
1033 info.label = "Relay 1 (reset)";
1034 break;
1035 case 5:
1036 info.propName = "RELAY_2";
1037 info.label = "Relay 2 (heater)";
1038 break;
1039 case 6:
1040 info.propName = "RELAY_3";
1041 info.label = "Relay 3";
1042 break;
1043 case 7:
1044 info.propName = "RELAY_4";
1045 info.label = "Relay 4";
1046 break;
1047 default:
1048 LOG_ERROR("invalid relay index");
1049 break;
1050 }
1051 return info;
1052}
1053
1055{
1056 switch(index)
1057 {
1058 case 0:
1059 return getInputState(OUT_CCD);
1060 case 1:
1061 return getInputState(OUT_SCOPE);
1062 case 2:
1063 return getInputState(OUT_LIGHT);
1064 case 3:
1065 return getInputState(OUT_FAN);
1066 case 4:
1067 return getInputState(OUT_RELAY1);
1068 case 5:
1069 return getInputState(OUT_RELAY2);
1070 case 6:
1071 return getInputState(OUT_RELAY3);
1072 case 7:
1073 return getInputState(OUT_RELAY4);
1074 default:
1075 LOG_ERROR("invalid relay index");
1076 break;
1077 }
1078 return ISS_OFF;
1079}
1080
1082{
1083 switch(index)
1084 {
1085 case 0:
1086 setOutputState(OUT_CCD, state);
1087 break;
1088 case 1:
1089 setOutputState(OUT_SCOPE, state);
1090 break;
1091 case 2:
1092 setOutputState(OUT_LIGHT, state);
1093 break;
1094 case 3:
1095 setOutputState(OUT_FAN, state);
1096 break;
1097 case 4:
1098 setOutputState(OUT_RELAY1, state);
1099 break;
1100 case 5:
1101 setOutputState(OUT_RELAY2, state);
1102 break;
1103 case 6:
1104 setOutputState(OUT_RELAY3, state);
1105 break;
1106 case 7:
1107 setOutputState(OUT_RELAY4, state);
1108 break;
1109 default:
1110 LOG_ERROR("invalid relay index");
1111 break;
1112 }
1113}
1114
1116{
1117 return 12;
1118}
1119
1121{
1123
1124 switch(index)
1125 {
1126 case 0:
1127 info.propName = "AZ_COUNTER";
1128 info.label = "Az counter";
1129 break;
1130 case 1:
1131 info.propName = "HOME";
1132 info.label = "Dome at home";
1133 break;
1134 case 2:
1135 info.propName = "OPEN_1";
1136 info.label = "Shutter 1 open";
1137 break;
1138 case 3:
1139 info.propName = "CLOSE_1";
1140 info.label = "Shutter 1 closed";
1141 break;
1142 case 4:
1143 info.propName = "OPEN_2";
1144 info.label = "Shutter 2 open";
1145 break;
1146 case 5:
1147 info.propName = "CLOSE_2";
1148 info.label = "Shutter 2 closed";
1149 break;
1150 case 6:
1151 info.propName = "SCOPE_HOME";
1152 info.label = "Scope at home";
1153 break;
1154 case 7:
1155 info.propName = "RAIN";
1156 info.label = "Rain sensor";
1157 break;
1158 case 8:
1159 info.propName = "CLOUD";
1160 info.label = "Cloud sensor";
1161 break;
1162 case 9:
1163 info.propName = "SAFE";
1164 info.label = "Observatory safe";
1165 break;
1166 case 10:
1167 info.propName = "LINK";
1168 info.label = "Rotary link";
1169 break;
1170 case 11:
1171 info.propName = "FREE";
1172 info.label = "Free input";
1173 break;
1174 default:
1175 LOG_ERROR("invalid input index");
1176 break;
1177 }
1178 return info;
1179}
1180
1182{
1183 switch(index)
1184 {
1185 case 0:
1186 return getInputState(IN_ENCODER);
1187 case 1:
1188 return getInputState(IN_HOME);
1189 case 2:
1190 return getInputState(IN_OPEN1);
1191 case 3:
1192 return getInputState(IN_CLOSED1);
1193 case 4:
1194 return getInputState(IN_OPEN2);
1195 case 5:
1196 return getInputState(IN_CLOSED2);
1197 case 6:
1198 return getInputState(IN_S_HOME);
1199 case 7:
1200 return getInputState(IN_CLOUDS);
1201 case 8:
1202 return getInputState(IN_CLOUD);
1203 case 9:
1204 return getInputState(IN_SAFE);
1205 case 10:
1206 return getInputState(IN_ROT_LINK);
1207 case 11:
1208 return getInputState(IN_FREE);
1209 default:
1210 LOG_ERROR("invalid input index");
1211 break;
1212 }
1213 return ISS_OFF;
1214}
1215
1217{
1218 uint8_t negate = 0;
1219 switch(polarity)
1220 {
1221 case ACTIVE_HIGH:
1222 negate = 0;
1223 break;
1224 case ACTIVE_LOW:
1225 negate = 1;
1226 break;
1227 }
1228
1229 writeU8(NegHomeSensorActiveState, negate);
1230}
virtual void calibrate() override
virtual void abort() override
virtual void getFirmwareVersions(double &main, double &rotary) override
virtual double getSensorValue(size_t index) override
virtual ISState getInputValue(size_t index) override
virtual int updateState() override
virtual int getRotationCounterExt() override
virtual uint32_t getStepsPerRevolution() override
virtual size_t getNumberOfRelays() override
virtual size_t getNumberOfInputs() override
virtual ISState getRelayState(size_t index) override
virtual int setOutputState(AbstractOutput output, ISState state) override
virtual void resetCounter() override
virtual uint32_t getStatus() override
virtual ISState getInputState(AbstractInput input) override
virtual void findHome() override
virtual bool detect() override
virtual size_t getNumberOfSensors() override
virtual int getRotationCounter() override
virtual RelayInfo getRelayInfo(size_t index) override
virtual bool isCalibrationNeeded() override
virtual SensorInfo getSensorInfo(size_t index) override
virtual void setRelayState(size_t index, ISState state) override
virtual void controlShutter(ShutterOperation operation) override
virtual void setHomeSensorPolarity(HomeSensorPolarity polarity) override
virtual InputInfo getInputInfo(size_t index) override
virtual void move(int steps) 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(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
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
uint8_t cmd[4]
Definition pwc-ioctl.h:2
#define SCOPEDOME_TIMEOUT