Instrument Neutral Distributed Interface INDI 2.2.5
domepro2.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2020 Jasem Mutlaq. All rights reserved.
3
4 Astrometric Solutions DomePro2 INDI Driver
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9 .
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14 .
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*******************************************************************************/
20
21#include "domepro2.h"
22
23#include "indicom.h"
25
26#include <cmath>
27#include <cstring>
28#include <memory>
29#include <regex>
30#include <termios.h>
31
32static std::unique_ptr<DomePro2> domepro2(new DomePro2());
33
45
47{
49 // Firmware & Hardware versions
50 VersionTP[VERSION_FIRMWARE].fill("VERSION_FIRMWARE", "Firmware", "NA");
51 VersionTP[VERSION_HARDWARE].fill("VERSION_HARDWARE", "Hardware", "NA");
52 VersionTP.fill(getDeviceName(), "VERSION", "Version", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
53
54 // Dome & Shutter statuses
55 StatusTP[STATUS_DOME].fill("STATUS_DOME", "Dome", "NA");
56 StatusTP[STATUS_SHUTTER].fill("STATUS_SHUTTER", "Shutter", "NA");
57 StatusTP.fill(getDeviceName(), "STATUS", "Status", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
58
59 // Settings
60 SettingsNP[SETTINGS_AZ_CPR].fill("SETTINGS_AZ_CPR", "Az CPR (steps)", "%.f", 0x20, 0x40000000, 0, 0);
61 SettingsNP[SETTINGS_AZ_COAST].fill("SETTINGS_AZ_COAST", "Az Coast (deg)", "%.2f", 0, 15, 0, 0);
62 SettingsNP[SETTINGS_AZ_HOME].fill("SETTINGS_AZ_HOME", "Az Home (deg)", "%.2f", 0, 360, 0, 0);
63 SettingsNP[SETTINGS_AZ_PARK].fill("SETTINGS_AZ_PARK", "Az Park (deg)", "%.2f", 0, 360, 0, 0);
64 SettingsNP[SETTINGS_AZ_STALL_COUNT].fill("SETTINGS_AZ_STALL_COUNT", "Az Stall Count (steps)", "%.f", 0, 0x40000000,
65 0, 0);
66 SettingsNP.fill(getDeviceName(), "SETTINGS", "Settings", SETTINGS_TAB, IP_RW, 60, IPS_IDLE);
67
68 // Home
69 HomeSP[HOME_DISCOVER].fill("HOME_DISCOVER", "Discover", ISS_OFF);
70 HomeSP[HOME_GOTO].fill("HOME_GOTO", "Goto", ISS_OFF);
71 HomeSP.fill(getDeviceName(), "HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_OK);
72
74
77
78 return true;
79}
80
84bool DomePro2::setupInitialParameters()
85{
86 if (InitPark())
87 {
88 // If loading parking data is successful, we just set the default parking values.
90 }
91 else
92 {
93 // Otherwise, we set all parking data to default in case no parking data is found.
94 SetAxis1Park(0);
96 }
97
98 if (getFirmwareVersion() && getHardwareConfig())
99 VersionTP.setState(IPS_OK);
100
101 if (getDomeStatus() && getShutterStatus())
102 StatusTP.setState(IPS_OK);
103
104 if (getDomeAzCPR() && getDomeAzCoast() && getDomeHomeAz() && getDomeParkAz() && getDomeAzStallCount())
105 SettingsNP.setState(IPS_OK);
106
107 if (getDomeAzPos())
109
110 return true;
111}
112
117{
118 return getFirmwareVersion();
119}
120
125{
126 return "DomePro2";
127}
128
133{
135
136 if (isConnected())
137 {
138 setupInitialParameters();
139
140 defineProperty(VersionTP);
141 defineProperty(StatusTP);
142 defineProperty(SettingsNP);
143 defineProperty(HomeSP);
144 }
145 else
146 {
147 deleteProperty(VersionTP);
148 deleteProperty(StatusTP);
149 deleteProperty(SettingsNP);
150 deleteProperty(HomeSP);
151 }
152
153 return true;
154}
155
159bool DomePro2::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
160{
161 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
162 {
163 // Home
164 if (HomeSP.isNameMatch(name))
165 {
166 HomeSP.reset();
167 for (size_t i = 0; i < HomeSP.count(); i++)
168 {
169 if (states[i] != ISS_ON)
170 continue;
171
172 if (HomeSP[HOME_GOTO].isNameMatch(names[i]))
173 {
174 if (!gotoHomeDomeAz())
175 {
176 HomeSP.setState(IPS_ALERT);
177 LOG_ERROR("Failed to go to Home Dome Az.");
178 }
179 else
180 {
181 HomeSP[HOME_GOTO].setState(ISS_ON);
182 HomeSP.setState(IPS_BUSY);
183 }
184 }
185 else if (HomeSP[HOME_DISCOVER].isNameMatch(names[i]))
186 {
187 if (!discoverHomeDomeAz())
188 {
189 HomeSP.setState(IPS_ALERT);
190 LOG_ERROR("Failed to discover Home Dome Az.");
191 }
192 else
193 {
194 HomeSP[HOME_DISCOVER].setState(ISS_ON);
195 HomeSP.setState(IPS_BUSY);
196 }
197 }
198 }
199
200 HomeSP.apply();
201 return true;
202 }
203
204 }
205
206 return INDI::Dome::ISNewSwitch(dev, name, states, names, n);
207}
208
212
213bool DomePro2::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
214{
215 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
216 {
218 // Settings
220 if (SettingsNP.isNameMatch(name))
221 {
222 bool allSet = true;
223 for (size_t i = 0; i < SettingsNP.count(); i++)
224 {
225 if (SettingsNP[SETTINGS_AZ_CPR].isNameMatch(names[i]))
226 {
227 if (setDomeAzCPR(static_cast<uint32_t>(values[i])))
228 SettingsNP[SETTINGS_AZ_CPR].setValue(values[i]);
229 else
230 {
231 allSet = false;
232 LOG_ERROR("Failed to set Dome AZ CPR.");
233 }
234 }
235 else if (SettingsNP[SETTINGS_AZ_COAST].isNameMatch(names[i]))
236 {
237 if (setDomeAzCoast(static_cast<uint32_t>(values[i])))
238 SettingsNP[SETTINGS_AZ_COAST].setValue(values[i]);
239 else
240 {
241 allSet = false;
242 LOG_ERROR("Failed to set Dome AZ Coast.");
243 }
244 }
245 else if (SettingsNP[SETTINGS_AZ_HOME].isNameMatch(names[i]))
246 {
247 if (setDomeHomeAz(static_cast<uint32_t>(values[i])))
248 SettingsNP[SETTINGS_AZ_HOME].setValue(values[i]);
249 else
250 {
251 allSet = false;
252 LOG_ERROR("Failed to set Dome AZ Home.");
253 }
254 }
255 else if (SettingsNP[SETTINGS_AZ_PARK].isNameMatch(names[i]))
256 {
257 if (setDomeParkAz(static_cast<uint32_t>(values[i])))
258 SettingsNP[SETTINGS_AZ_PARK].setValue(values[i]);
259 else
260 {
261 allSet = false;
262 LOG_ERROR("Failed to set Dome AZ Park.");
263 }
264 }
265 else if (SettingsNP[SETTINGS_AZ_STALL_COUNT].isNameMatch(names[i]))
266 {
267 if (setDomeAzStallCount(static_cast<uint32_t>(values[i])))
268 SettingsNP[SETTINGS_AZ_STALL_COUNT].setValue(values[i]);
269 else
270 {
271 allSet = false;
272 LOG_ERROR("Failed to set Dome AZ Stall Count.");
273 }
274 }
275
276 }
277
278 SettingsNP.setState(allSet ? IPS_OK : IPS_ALERT);
279 SettingsNP.apply();
280 return true;
281 }
282
283 }
284
285 return INDI::Dome::ISNewNumber(dev, name, values, names, n);
286}
291{
292 if (!isConnected())
293 return;
294
295 double currentAz = DomeAbsPosNP[0].getValue();
296 if(getDomeAzPos() && std::abs(currentAz - DomeAbsPosNP[0].getValue()) > DOME_AZ_THRESHOLD)
298
299 std::string domeStatus = StatusTP[STATUS_DOME].getText();
300 std::string shutterStatus = StatusTP[STATUS_SHUTTER].getText();
301 if(getDomeStatus() && getShutterStatus() && (strcmp(domeStatus.c_str(), StatusTP[STATUS_DOME].getText()) != 0 ||
302 strcmp(shutterStatus.c_str(), StatusTP[STATUS_DOME].getText()) != 0))
303 {
305 {
306
307 if (StatusTP[STATUS_DOME].isNameMatch("Idle"))
308 {
309 if (getDomeState() == DOME_PARKING)
310 SetParked(true);
311
313
314 if (HomeSP.getState() == IPS_BUSY)
315 {
316 HomeSP.reset();
317 HomeSP.setState(IPS_IDLE);
318 HomeSP.apply();
319 }
320 }
321 }
322
324 {
325 int statusVal = processShutterStatus();
326 if (statusVal == 0x00)
328 else if (statusVal == 0x01)
330 else if ((statusVal >= 0x04 && statusVal <= 12) || statusVal >= 15)
332 else if (statusVal == 0x13)
334 }
335
336 StatusTP.apply();
337 }
338
340}
341
346{
347 INDI_UNUSED(az);
348 uint32_t steps = static_cast<uint32_t>(az * (SettingsNP[SETTINGS_AZ_CPR].getValue() / 360));
349 if (gotoDomeAz(steps))
350 return IPS_BUSY;
351 return IPS_ALERT;
352}
353
358{
359 targetAz = DomeAbsPosNP[0].getValue() + azDiff;
360
361 if (targetAz < DomeAbsPosNP[0].getMin())
362 targetAz += DomeAbsPosNP[0].getMax();
363 if (targetAz > DomeAbsPosNP[0].getMax())
364 targetAz -= DomeAbsPosNP[0].getMax();
365
366 // It will take a few cycles to reach final position
367 return MoveAbs(targetAz);
368}
369
373bool DomePro2::Sync(double az)
374{
375 //INDI_UNUSED(az);
376 if(calibrateDomeAz(az))
377 return true;
378 return false;
379}
380
385{
386 // INDI_UNUSED(dir);
387 // INDI_UNUSED(operation);
388 if (operation == MOTION_STOP)
389 {
390 if(killDomeAzMovement())
391 return IPS_OK;
392 }
393 else if (dir == DOME_CCW)
394 {
395 if(setDomeLeftOn())
396 return IPS_BUSY;
397 }
398 else if (dir == DOME_CW)
399 {
400 if(setDomeRightOn())
401 return IPS_BUSY;
402 }
403
404 return IPS_ALERT;
405}
406
411{
412 //targetAz = GetAxis1Park();
413 return (gotoDomePark() ? IPS_BUSY : IPS_ALERT);
414 //return MoveAbs(targetAz);
415}
416
421{
422 return IPS_OK;
423}
424
429{
430 if (operation == SHUTTER_OPEN)
431 {
432 if (openDomeShutters())
433 return IPS_BUSY;
434 }
435 else if (operation == SHUTTER_CLOSE)
436 {
437 if (closeDomeShutters())
438 return IPS_BUSY;
439 }
440 return IPS_ALERT;
441}
442
447{
448 if (!killDomeAzMovement())
449 return false;
450
451 if (getShutterState() == SHUTTER_MOVING && killDomeShutterMovement())
452 {
454 }
455
456 if (ParkSP.getState() == IPS_BUSY)
457 {
458 SetParked(false);
459 }
460
461 if (HomeSP.getState() == IPS_BUSY)
462 {
463 HomeSP.reset();
464 HomeSP.setState(IPS_IDLE);
465 HomeSP.apply();
466 }
467
468 return true;
469}
470
475{
477
478 return true;
479}
480
485{
486 SetAxis1Park(DomeAbsPosNP[0].getValue());
487 return true;
488}
489
494{
495 // By default set position to 90
496 SetAxis1Park(90);
497 return true;
498}
499
503uint8_t DomePro2::processShutterStatus()
504{
505 if (StatusTP[STATUS_SHUTTER].isNameMatch("Opened"))
506 return 0;
507 else if (StatusTP[STATUS_SHUTTER].isNameMatch("Closed"))
508 return 1;
509 else if (StatusTP[STATUS_SHUTTER].isNameMatch("Opening"))
510 return 2;
511 else if (StatusTP[STATUS_SHUTTER].isNameMatch("Closing"))
512 return 3;
513 else if (StatusTP[STATUS_SHUTTER].isNameMatch("ShutterError"))
514 return 4;
515 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter module is not communicating to the azimuth module"))
516 return 5;
517 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 opposite direction timeout error on open occurred"))
518 return 6;
519 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 opposite direction timeout error on close occurred"))
520 return 7;
521 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 opposite direction timeout error on open occurred"))
522 return 8;
523 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 opposite direction timeout error on close occurred"))
524 return 9;
525 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 completion timeout error on open occurred"))
526 return 10;
527 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 completion timeout error on close occurred"))
528 return 11;
529 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 completion timeout error on open occurred"))
530 return 12;
531 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 completion timeout error on close occurred"))
532 return 13;
533 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 limit fault on open occurred"))
534 return 14;
535 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 limit fault on close occurred"))
536 return 15;
537 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 limit fault on open occurred"))
538 return 16;
539 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 limit fault on close occurred"))
540 return 17;
541 else if (StatusTP[STATUS_SHUTTER].isNameMatch("Shutter disabled (Shutter Enable input is not asserted)"))
542 return 18;
543 else if (StatusTP[STATUS_SHUTTER].isNameMatch("Intermediate"))
544 return 19;
545 else if (StatusTP[STATUS_SHUTTER].isNameMatch("GoTo"))
546 return 20;
547 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 OCP trip on open occurred"))
548 return 21;
549 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 1 OCP trip on close occurred"))
550 return 22;
551 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 OCP trip on open occurred"))
552 return 23;
553 else if (StatusTP[STATUS_SHUTTER].isNameMatch("shutter 2 OCP trip on close occurred"))
554 return 24;
555 return 25;
556}
557
561bool DomePro2::getFirmwareVersion()
562{
563 char res[DRIVER_LEN] = {0};
564 if (sendCommand("DGfv", res) == false)
565 return false;
566
567 int version = 0;
568 if (sscanf(res, "%X", &version) == 1)
569 {
570 char versionString[DRIVER_LEN] = {0};
571 snprintf(versionString, DRIVER_LEN, "%d", version);
572 VersionTP[VERSION_FIRMWARE].setText(versionString);
573 return true;
574 }
575
576 return false;
577}
578
582bool DomePro2::getHardwareConfig()
583{
584 char res[DRIVER_LEN] = {0};
585 if (sendCommand("DGhc", res) == false)
586 return false;
587
588 uint32_t config = 0;
589 if (sscanf(res, "%X", &config) == 1)
590 {
591 char configString[DRIVER_LEN] = {0};
592 uint8_t index = static_cast<uint8_t>(config);
593 if (DomeHardware.count(index))
594 {
595 snprintf(configString, DRIVER_LEN, "%s", DomeHardware.at(index).c_str());
596 VersionTP[VERSION_HARDWARE].setText(configString);
597
598 }
599 else
600 {
601 LOGF_WARN("Unknown model detected %d", config);
602 }
603
604 return true;
605 }
606
607 return false;
608}
609
613bool DomePro2::getDomeStatus()
614{
615 char res[DRIVER_LEN] = {0};
616 if (sendCommand("DGam", res) == false)
617 return false;
618
619 if (DomeStatus.count(res))
620 {
621 StatusTP[STATUS_DOME].setText(DomeStatus.at(res).c_str());
622 return true;
623 }
624 else
625 {
626 LOGF_WARN("Unknown dome status detected %d", res);
627 return false;
628 }
629}
630
634bool DomePro2::getShutterStatus()
635{
636 char res[DRIVER_LEN] = {0};
637 if (sendCommand("DGsx", res) == false)
638 return false;
639
640 uint32_t status = 0;
641 if (sscanf(res, "%X", &status) == 1)
642 {
643 char statusString[DRIVER_LEN] = {0};
644 uint8_t index = static_cast<uint8_t>(status);
645 if (ShutterStatus.count(index))
646 {
647 snprintf(statusString, DRIVER_LEN, "%s", ShutterStatus.at(index).c_str());
648 StatusTP[STATUS_SHUTTER].setText(statusString);
649
650 }
651 else
652 {
653 LOGF_WARN("Unknown shutter status detected %d", status);
654 }
655
656 return true;
657 }
658
659 return false;
660}
661
665bool DomePro2::getDomeAzCPR()
666{
667 char res[DRIVER_LEN] = {0};
668 if (sendCommand("DGcp", res) == false)
669 return false;
670
671 uint32_t cpr = 0;
672 if (sscanf(res, "%X", &cpr) == 1)
673 {
674 SettingsNP[SETTINGS_AZ_CPR].setValue(cpr);
675 return true;
676 }
677
678 return false;
679}
680
684bool DomePro2::setDomeAzCPR(uint32_t cpr)
685{
686 char cmd[DRIVER_LEN] = {0};
687 if (cpr < 0x20 || cpr > 0x40000000)
688 {
689 LOG_ERROR("CPR value out of bounds (32 to 1,073,741,824)");
690 return false;
691 }
692 else if (cpr % 2 != 0)
693 {
694 LOG_ERROR("CPR value must be an even number");
695 return false;
696 }
697 snprintf(cmd, DRIVER_LEN, "DScp0x%08X", cpr);
698 if (sendCommand(cmd) == false)
699 return false;
700 return true;
701}
702
706bool DomePro2::getDomeAzCoast()
707{
708 char res[DRIVER_LEN] = {0};
709 if (sendCommand("DGco", res) == false)
710 return false;
711
712 uint32_t coast = 0;
713 if (sscanf(res, "%X", &coast) == 1)
714 {
715 SettingsNP[SETTINGS_AZ_COAST].setValue(coast * (360 / SettingsNP[SETTINGS_AZ_CPR].getValue()));
716 return true;
717 }
718
719 return false;
720}
721
725bool DomePro2::setDomeAzCoast(uint32_t az)
726{
727 char cmd[DRIVER_LEN] = {0};
728 uint32_t steps = static_cast<uint32_t>(az * (SettingsNP[SETTINGS_AZ_CPR].getValue() / 360));
729 // if (coast > 0x4000)
730 // {
731 // LOG_ERROR("Coast value out of bounds (0 to 16,384)");
732 // return false;
733 // }
734 snprintf(cmd, DRIVER_LEN, "DSco0x%08X", steps);
735 if (sendCommand(cmd) == false)
736 return false;
737 return true;
738}
739
743bool DomePro2::getDomeHomeAz()
744{
745 char res[DRIVER_LEN] = {0};
746 if (sendCommand("DGha", res) == false)
747 return false;
748
749 uint32_t home = 0;
750 if (sscanf(res, "%X", &home) == 1)
751 {
752 SettingsNP[SETTINGS_AZ_HOME].setValue(home * (360 / SettingsNP[SETTINGS_AZ_CPR].getValue()));
753 return true;
754 }
755
756 return false;
757}
758
762bool DomePro2::setDomeHomeAz(uint32_t az)
763{
764 char cmd[DRIVER_LEN] = {0};
765 uint32_t steps = static_cast<uint32_t>(az * (SettingsNP[SETTINGS_AZ_CPR].getValue() / 360));
766 // if (home >= SettingsN[SETTINGS_AZ_CPR].value)
767 // {
768 // char err[DRIVER_LEN] = {0};
769 // snprintf(err, DRIVER_LEN, "Home value out of bounds (0 to %.f, value has to be less than CPR)",
770 // SettingsN[SETTINGS_AZ_CPR].value - 1);
771 // LOG_ERROR(err);
772 // return false;
773 // }
774 snprintf(cmd, DRIVER_LEN, "DSha0x%08X", steps);
775 if (sendCommand(cmd) == false)
776 return false;
777 return true;
778}
779
783bool DomePro2::getDomeParkAz()
784{
785 char res[DRIVER_LEN] = {0};
786 if (sendCommand("DGpa", res) == false)
787 return false;
788
789 uint32_t park = 0;
790 if (sscanf(res, "%X", &park) == 1)
791 {
792 SettingsNP[SETTINGS_AZ_PARK].setValue(park * (360 / SettingsNP[SETTINGS_AZ_CPR].getValue()));
793 return true;
794 }
795
796 return false;
797}
798
802bool DomePro2::setDomeParkAz(uint32_t az)
803{
804 char cmd[DRIVER_LEN] = {0};
805 uint32_t steps = static_cast<uint32_t>(az * (SettingsNP[SETTINGS_AZ_CPR].getValue() / 360));
806 // if (park >= SettingsN[SETTINGS_AZ_CPR].value)
807 // {
808 // char err[DRIVER_LEN] = {0};
809 // snprintf(err, DRIVER_LEN, "Park value out of bounds (0 to %.f, value has to be less than CPR)",
810 // SettingsN[SETTINGS_AZ_CPR].value - 1);
811 // LOG_ERROR(err);
812 // return false;
813 // }
814 snprintf(cmd, DRIVER_LEN, "DSpa0x%08X", steps);
815 if (sendCommand(cmd) == false)
816 return false;
817 return true;
818}
819
823bool DomePro2::calibrateDomeAz(double az)
824{
825 char cmd[DRIVER_LEN] = {0};
826 uint32_t steps = static_cast<uint32_t>(az * (SettingsNP[SETTINGS_AZ_CPR].getValue() / 360));
827 // if (steps >= SettingsN[SETTINGS_AZ_CPR].value)
828 // {
829 // char err[DRIVER_LEN] = {0};
830 // snprintf(err, DRIVER_LEN, "Degree value out of bounds");
831 // LOG_ERROR(err);
832 // return false;
833 // }
834 snprintf(cmd, DRIVER_LEN, "DSca0x%08X", steps);
835 if (sendCommand(cmd) == false)
836 return false;
837 return true;
838}
839
843bool DomePro2::getDomeAzStallCount()
844{
845 char res[DRIVER_LEN] = {0};
846 if (sendCommand("DGas", res) == false)
847 return false;
848
849 uint32_t count = 0;
850 if (sscanf(res, "%X", &count) == 1)
851 {
852 SettingsNP[SETTINGS_AZ_STALL_COUNT].setValue(count);
853 return true;
854 }
855
856 return false;
857}
858
862bool DomePro2::setDomeAzStallCount(uint32_t count)
863{
864 char cmd[DRIVER_LEN] = {0};
865 snprintf(cmd, DRIVER_LEN, "DSha0x%08X", count);
866 if (sendCommand(cmd) == false)
867 return false;
868 return true;
869}
870
874bool DomePro2::getDomeAzPos()
875{
876 char res[DRIVER_LEN] = {0};
877 if (sendCommand("DGap", res) == false)
878 return false;
879
880 uint32_t pos = 0;
881 if (sscanf(res, "%X", &pos) == 1)
882 {
883 DomeAbsPosNP[0].setValue(pos * (360 / SettingsNP[SETTINGS_AZ_CPR].getValue()));
884 return true;
885 }
886
887 return false;
888}
889
893bool DomePro2::gotoDomeAz(uint32_t az)
894{
895 char cmd[DRIVER_LEN] = {0};
896 if (az >= SettingsNP[SETTINGS_AZ_CPR].getValue())
897 return false;
898 snprintf(cmd, DRIVER_LEN, "DSgo0x%08X", az);
899 if (sendCommand(cmd) == false)
900 return false;
901 return true;
902}
903
907bool DomePro2::gotoDomePark()
908{
909 if (sendCommand("DSgp") == false)
910 return false;
911 return true;
912}
913
917bool DomePro2::killDomeAzMovement()
918{
919 if (sendCommand("DXxa") == false)
920 return false;
921 return true;
922}
923
927bool DomePro2::killDomeShutterMovement()
928{
929 if (sendCommand("DXxs") == false)
930 return false;
931 return true;
932}
933
937bool DomePro2::openDomeShutters()
938{
939 if (sendCommand("DSso") == false)
940 return false;
941 return true;
942}
943
947bool DomePro2::closeDomeShutters()
948{
949 if (sendCommand("DSsc") == false)
950 return false;
951 return true;
952}
953
957bool DomePro2::gotoHomeDomeAz()
958{
959 if (sendCommand("DSah") == false)
960 return false;
961 return true;
962}
963
967bool DomePro2::discoverHomeDomeAz()
968{
969 if (sendCommand("DSdh") == false)
970 return false;
971 return true;
972}
973
977bool DomePro2::setDomeLeftOn()
978{
979 if (sendCommand("DSol") == false)
980 return false;
981 return true;
982}
983
987bool DomePro2::setDomeRightOn()
988{
989 if (sendCommand("DSor") == false)
990 return false;
991 return true;
992}
993
997bool DomePro2::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
998{
999 int nbytes_written = 0, nbytes_read = 0, rc = -1;
1000
1001 tcflush(PortFD, TCIOFLUSH);
1002
1003 if (cmd_len > 0)
1004 {
1005 char hex_cmd[DRIVER_LEN * 3] = {0};
1006 hexDump(hex_cmd, cmd, cmd_len);
1007 LOGF_DEBUG("CMD <%s>", hex_cmd);
1008 rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
1009 }
1010 else
1011 {
1012 LOGF_DEBUG("CMD <%s>", cmd);
1013
1014 char formatted_command[DRIVER_LEN] = {0};
1015 snprintf(formatted_command, DRIVER_LEN, "!%s;", cmd);
1016 rc = tty_write_string(PortFD, formatted_command, &nbytes_written);
1017 }
1018
1019 if (rc != TTY_OK)
1020 {
1021 char errstr[MAXRBUF] = {0};
1022 tty_error_msg(rc, errstr, MAXRBUF);
1023 LOGF_ERROR("Serial write error: %s.", errstr);
1024 return false;
1025 }
1026
1027 if (res == nullptr)
1028 return true;
1029
1030 if (res_len > 0)
1031 rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
1032 else
1033 rc = tty_nread_section(PortFD, res, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
1034
1035 if (rc != TTY_OK)
1036 {
1037 char errstr[MAXRBUF] = {0};
1038 tty_error_msg(rc, errstr, MAXRBUF);
1039 LOGF_ERROR("Serial read error: %s.", errstr);
1040 return false;
1041 }
1042
1043 if (res_len > 0)
1044 {
1045 char hex_res[DRIVER_LEN * 3] = {0};
1046 hexDump(hex_res, res, res_len);
1047 LOGF_DEBUG("RES <%s>", hex_res);
1048 }
1049 else
1050 {
1051 // Remove extra \r
1052 res[nbytes_read - 1] = 0;
1053 LOGF_DEBUG("RES <%s>", res);
1054 }
1055
1056 tcflush(PortFD, TCIOFLUSH);
1057
1058 return true;
1059}
1060
1064void DomePro2::hexDump(char * buf, const char * data, int size)
1065{
1066 for (int i = 0; i < size; i++)
1067 sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
1068
1069 if (size > 0)
1070 buf[3 * size - 1] = '\0';
1071}
1072
1076std::vector<std::string> DomePro2::split(const std::string &input, const std::string &regex)
1077{
1078 // passing -1 as the submatch index parameter performs splitting
1079 std::regex re(regex);
1080 std::sregex_token_iterator
1081 first{input.begin(), input.end(), re, -1},
1082 last;
1083 return {first, last};
1084}
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition domepro2.cpp:290
virtual IPState UnPark() override
UnPark dome. The action of the Unpark command is dome specific, but it may include opening the shutte...
Definition domepro2.cpp:420
virtual IPState ControlShutter(ShutterOperation operation) override
Open or Close shutter.
Definition domepro2.cpp:428
virtual bool Sync(double az) override
Sync sets the dome current azimuth as the supplied azimuth position.
Definition domepro2.cpp:373
virtual const char * getDefaultName() override
Definition domepro2.cpp:124
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition domepro2.cpp:159
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition domepro2.cpp:484
virtual IPState MoveRel(double azDiff) override
Move the Dome to an relative position.
Definition domepro2.cpp:357
virtual IPState MoveAbs(double az) override
Move the Dome to an absolute azimuth.
Definition domepro2.cpp:345
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
Definition domepro2.cpp:46
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition domepro2.cpp:493
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation) override
Move the Dome in a particular direction.
Definition domepro2.cpp:384
virtual bool Handshake() override
perform handshake with device to check communication
Definition domepro2.cpp:116
virtual bool Abort() override
Abort all dome motion.
Definition domepro2.cpp:446
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
Definition domepro2.cpp:474
virtual IPState Park() override
Goto Park Position. The park position is an absolute azimuth value.
Definition domepro2.cpp:410
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition domepro2.cpp:213
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition domepro2.cpp:132
bool isConnected() const
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.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
void SetDomeCapability(uint32_t cap)
SetDomeCapability set the dome capabilities. All capabilities must be initialized.
ShutterState m_ShutterState
Definition indidome.h:612
void SetAxis1Park(double value)
SetRAPark Set current AZ parking position. The data park file (stored in ~/.indi/ParkData....
void SetAxis1ParkDefault(double steps)
SetAxis1Park Set default AZ parking position.
ShutterOperation
Shutter operation command.
Definition indidome.h:114
@ SHUTTER_CLOSE
Definition indidome.h:116
DomeMotionCommand
Definition indidome.h:97
@ MOTION_STOP
Definition indidome.h:99
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
Definition indidome.cpp:105
@ DOME_CAN_PARK
Definition indidome.h:159
@ DOME_CAN_ABS_MOVE
Definition indidome.h:157
@ DOME_HAS_SHUTTER
Definition indidome.h:161
@ DOME_CAN_REL_MOVE
Definition indidome.h:158
@ DOME_CAN_ABORT
Definition indidome.h:156
@ DOME_CAN_SYNC
Definition indidome.h:160
@ SHUTTER_ERROR
Definition indidome.h:151
@ SHUTTER_MOVING
Definition indidome.h:149
@ SHUTTER_UNKNOWN
Definition indidome.h:150
@ SHUTTER_OPENED
Definition indidome.h:147
@ SHUTTER_CLOSED
Definition indidome.h:148
INDI::PropertySwitch ParkSP
Definition indidome.h:548
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition indidome.cpp:284
INDI::PropertyNumber DomeAbsPosNP
Definition indidome.h:536
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition indidome.cpp:503
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
void setShutterState(const ShutterState &value)
void setDomeState(const DomeState &value)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Connection::Serial * serialConnection
Definition indidome.h:607
void SetParkDataType(DomeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
ShutterState getShutterState() const
Definition indidome.h:291
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition indidome.cpp:394
DomeState getDomeState() const
Definition indidome.h:285
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
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)
INDI::PropertyViewText * getText() const
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_ATMOST1
Definition indiapi.h:172
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
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_WARN(fmt,...)
Definition indilogger.h:81
#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 getDeviceName
bool park(const int fd)
uint8_t cmd[4]
Definition pwc-ioctl.h:2