Instrument Neutral Distributed Interface INDI  2.0.2
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 <inttypes.h>
29 #include <memory>
30 #include <regex>
31 #include <termios.h>
32 
33 static std::unique_ptr<DomePro2> domepro2(new DomePro2());
34 
36 {
38 
45 }
46 
48 {
50  // Firmware & Hardware versions
51  IUFillText(&VersionT[VERSION_FIRMWARE], "VERSION_FIRMWARE", "Firmware", "NA");
52  IUFillText(&VersionT[VERSION_HARDWARE], "VERSION_HARDWARE", "Hardware", "NA");
53  IUFillTextVector(&VersionTP, VersionT, 2, getDeviceName(), "VERSION", "Version", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
54 
55  // Dome & Shutter statuses
56  IUFillText(&StatusT[STATUS_DOME], "STATUS_DOME", "Dome", "NA");
57  IUFillText(&StatusT[STATUS_SHUTTER], "STATUS_SHUTTER", "Shutter", "NA");
58  IUFillTextVector(&StatusTP, StatusT, 2, getDeviceName(), "STATUS", "Status", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
59 
60  // Settings
61  IUFillNumber(&SettingsN[SETTINGS_AZ_CPR], "SETTINGS_AZ_CPR", "Az CPR (steps)", "%.f", 0x20, 0x40000000, 0, 0);
62  IUFillNumber(&SettingsN[SETTINGS_AZ_COAST], "SETTINGS_AZ_COAST", "Az Coast (deg)", "%.2f", 0, 15, 0, 0);
63  IUFillNumber(&SettingsN[SETTINGS_AZ_HOME], "SETTINGS_AZ_HOME", "Az Home (deg)", "%.2f", 0, 360, 0, 0);
64  IUFillNumber(&SettingsN[SETTINGS_AZ_PARK], "SETTINGS_AZ_PARK", "Az Park (deg)", "%.2f", 0, 360, 0, 0);
65  IUFillNumber(&SettingsN[SETTINGS_AZ_STALL_COUNT], "SETTINGS_AZ_STALL_COUNT", "Az Stall Count (steps)", "%.f", 0, 0x40000000,
66  0, 0);
67  IUFillNumberVector(&SettingsNP, SettingsN, 5, getDeviceName(), "SETTINGS", "Settings", SETTINGS_TAB, IP_RW, 60, IPS_IDLE);
68 
69  // Home
70  IUFillSwitch(&HomeS[HOME_DISCOVER], "HOME_DISCOVER", "Discover", ISS_OFF);
71  IUFillSwitch(&HomeS[HOME_GOTO], "HOME_GOTO", "Goto", ISS_OFF);
72  IUFillSwitchVector(&HomeSP, HomeS, 2, getDeviceName(), "HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_OK);
73 
75 
78 
79  return true;
80 }
81 
85 bool DomePro2::setupInitialParameters()
86 {
87  if (InitPark())
88  {
89  // If loading parking data is successful, we just set the default parking values.
91  }
92  else
93  {
94  // Otherwise, we set all parking data to default in case no parking data is found.
95  SetAxis1Park(0);
97  }
98 
99  if (getFirmwareVersion() && getHardwareConfig())
100  VersionTP.s = IPS_OK;
101 
102  if (getDomeStatus() && getShutterStatus())
103  StatusTP.s = IPS_OK;
104 
105  if (getDomeAzCPR() && getDomeAzCoast() && getDomeHomeAz() && getDomeParkAz() && getDomeAzStallCount())
106  SettingsNP.s = IPS_OK;
107 
108  if (getDomeAzPos())
109  IDSetNumber(&DomeAbsPosNP, nullptr);
110 
111  return true;
112 }
113 
118 {
119  return getFirmwareVersion();
120 }
121 
126 {
127  return "DomePro2";
128 }
129 
134 {
136 
137  if (isConnected())
138  {
139  setupInitialParameters();
140 
141  defineProperty(&VersionTP);
142  defineProperty(&StatusTP);
143  defineProperty(&SettingsNP);
144  defineProperty(&HomeSP);
145  }
146  else
147  {
148  deleteProperty(VersionTP.name);
149  deleteProperty(StatusTP.name);
150  deleteProperty(SettingsNP.name);
151  deleteProperty(HomeSP.name);
152  }
153 
154  return true;
155 }
156 
160 bool DomePro2::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
161 {
162  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
163  {
164  // Home
165  if (!strcmp(name, HomeSP.name))
166  {
167  IUResetSwitch(&HomeSP);
168  for (int i = 0; i < HomeSP.nsp; i++)
169  {
170  if (states[i] != ISS_ON)
171  continue;
172 
173  if (!strcmp(HomeS[HOME_GOTO].name, names[i]))
174  {
175  if (!gotoHomeDomeAz())
176  {
177  HomeSP.s = IPS_ALERT;
178  LOG_ERROR("Failed to go to Home Dome Az.");
179  }
180  else
181  {
182  HomeS[HOME_GOTO].s = ISS_ON;
183  HomeSP.s = IPS_BUSY;
184  }
185  }
186  else if (!strcmp(HomeS[HOME_DISCOVER].name, names[i]))
187  {
188  if (!discoverHomeDomeAz())
189  {
190  HomeSP.s = IPS_ALERT;
191  LOG_ERROR("Failed to discover Home Dome Az.");
192  }
193  else
194  {
195  HomeS[HOME_DISCOVER].s = ISS_ON;
196  HomeSP.s = IPS_BUSY;
197  }
198  }
199  }
200 
201  IDSetSwitch(&HomeSP, nullptr);
202  return true;
203  }
204 
205  }
206 
207  return INDI::Dome::ISNewSwitch(dev, name, states, names, n);
208 }
209 
213 
214 bool DomePro2::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
215 {
216  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
217  {
219  // Settings
221  if (!strcmp(name, SettingsNP.name))
222  {
223  bool allSet = true;
224  for (int i = 0; i < SettingsNP.nnp; i++)
225  {
226  if (!strcmp(SettingsN[SETTINGS_AZ_CPR].name, names[i]))
227  {
228  if (setDomeAzCPR(static_cast<uint32_t>(values[i])))
229  SettingsN[SETTINGS_AZ_CPR].value = values[i];
230  else
231  {
232  allSet = false;
233  LOG_ERROR("Failed to set Dome AZ CPR.");
234  }
235  }
236  else if (!strcmp(SettingsN[SETTINGS_AZ_COAST].name, names[i]))
237  {
238  if (setDomeAzCoast(static_cast<uint32_t>(values[i])))
239  SettingsN[SETTINGS_AZ_COAST].value = values[i];
240  else
241  {
242  allSet = false;
243  LOG_ERROR("Failed to set Dome AZ Coast.");
244  }
245  }
246  else if (!strcmp(SettingsN[SETTINGS_AZ_HOME].name, names[i]))
247  {
248  if (setDomeHomeAz(static_cast<uint32_t>(values[i])))
249  SettingsN[SETTINGS_AZ_HOME].value = values[i];
250  else
251  {
252  allSet = false;
253  LOG_ERROR("Failed to set Dome AZ Home.");
254  }
255  }
256  else if (!strcmp(SettingsN[SETTINGS_AZ_PARK].name, names[i]))
257  {
258  if (setDomeParkAz(static_cast<uint32_t>(values[i])))
259  SettingsN[SETTINGS_AZ_PARK].value = values[i];
260  else
261  {
262  allSet = false;
263  LOG_ERROR("Failed to set Dome AZ Park.");
264  }
265  }
266  else if (!strcmp(SettingsN[SETTINGS_AZ_STALL_COUNT].name, names[i]))
267  {
268  if (setDomeAzStallCount(static_cast<uint32_t>(values[i])))
269  SettingsN[SETTINGS_AZ_STALL_COUNT].value = values[i];
270  else
271  {
272  allSet = false;
273  LOG_ERROR("Failed to set Dome AZ Stall Count.");
274  }
275  }
276 
277  }
278 
279  SettingsNP.s = allSet ? IPS_OK : IPS_ALERT;
280  IDSetNumber(&SettingsNP, nullptr);
281  return true;
282  }
283 
284  }
285 
286  return INDI::Dome::ISNewNumber(dev, name, values, names, n);
287 }
292 {
293  if (!isConnected())
294  return;
295 
296  double currentAz = DomeAbsPosN[0].value;
297  if(getDomeAzPos() && std::abs(currentAz - DomeAbsPosN[0].value) > DOME_AZ_THRESHOLD)
298  IDSetNumber(&DomeAbsPosNP, nullptr);
299 
300  std::string domeStatus = StatusT[STATUS_DOME].text;
301  std::string shutterStatus = StatusT[STATUS_SHUTTER].text;
302  if(getDomeStatus() && getShutterStatus() && (strcmp(domeStatus.c_str(), StatusT[STATUS_DOME].text) != 0 ||
303  strcmp(shutterStatus.c_str(), StatusT[STATUS_DOME].text) != 0))
304  {
306  {
307 
308  if (!strcmp(StatusT[STATUS_DOME].text, "Idle"))
309  {
310  if (getDomeState() == DOME_PARKING)
311  SetParked(true);
312 
314 
315  if (HomeSP.s == IPS_BUSY)
316  {
317  IUResetSwitch(&HomeSP);
318  HomeSP.s = IPS_IDLE;
319  IDSetSwitch(&HomeSP, nullptr);
320  }
321  }
322  }
323 
325  {
326  int statusVal = processShutterStatus();
327  if (statusVal == 0x00)
329  else if (statusVal == 0x01)
331  else if ((statusVal >= 0x04 && statusVal <= 12) || statusVal >= 15)
333  else if (statusVal == 0x13)
335  }
336 
337  IDSetText(&StatusTP, nullptr);
338  }
339 
341 }
342 
347 {
348  INDI_UNUSED(az);
349  uint32_t steps = static_cast<uint32_t>(az * (SettingsN[SETTINGS_AZ_CPR].value / 360));
350  if (gotoDomeAz(steps))
351  return IPS_BUSY;
352  return IPS_ALERT;
353 }
354 
359 {
360  targetAz = DomeAbsPosN[0].value + azDiff;
361 
362  if (targetAz < DomeAbsPosN[0].min)
363  targetAz += DomeAbsPosN[0].max;
364  if (targetAz > DomeAbsPosN[0].max)
365  targetAz -= DomeAbsPosN[0].max;
366 
367  // It will take a few cycles to reach final position
368  return MoveAbs(targetAz);
369 }
370 
374 bool DomePro2::Sync(double az)
375 {
376  //INDI_UNUSED(az);
377  if(calibrateDomeAz(az))
378  return true;
379  return false;
380 }
381 
386 {
387  // INDI_UNUSED(dir);
388  // INDI_UNUSED(operation);
389  if (operation == MOTION_STOP)
390  {
391  if(killDomeAzMovement())
392  return IPS_OK;
393  }
394  else if (dir == DOME_CCW)
395  {
396  if(setDomeLeftOn())
397  return IPS_BUSY;
398  }
399  else if (dir == DOME_CW)
400  {
401  if(setDomeRightOn())
402  return IPS_BUSY;
403  }
404 
405  return IPS_ALERT;
406 }
407 
412 {
413  //targetAz = GetAxis1Park();
414  return (gotoDomePark() ? IPS_BUSY : IPS_ALERT);
415  //return MoveAbs(targetAz);
416 }
417 
422 {
423  return IPS_OK;
424 }
425 
430 {
431  if (operation == SHUTTER_OPEN)
432  {
433  if (openDomeShutters())
434  return IPS_BUSY;
435  }
436  else if (operation == SHUTTER_CLOSE)
437  {
438  if (closeDomeShutters())
439  return IPS_BUSY;
440  }
441  return IPS_ALERT;
442 }
443 
448 {
449  if (!killDomeAzMovement())
450  return false;
451 
452  if (getShutterState() == SHUTTER_MOVING && killDomeShutterMovement())
453  {
455  }
456 
457  if (ParkSP.s == IPS_BUSY)
458  {
459  SetParked(false);
460  }
461 
462  if (HomeSP.s == IPS_BUSY)
463  {
464  IUResetSwitch(&HomeSP);
465  HomeSP.s = IPS_IDLE;
466  IDSetSwitch(&HomeSP, nullptr);
467  }
468 
469  return true;
470 }
471 
476 {
478 
479  return true;
480 }
481 
486 {
487  SetAxis1Park(DomeAbsPosN[0].value);
488  return true;
489 }
490 
495 {
496  // By default set position to 90
497  SetAxis1Park(90);
498  return true;
499 }
500 
504 uint8_t DomePro2::processShutterStatus()
505 {
506  if (!strcmp(StatusT[STATUS_SHUTTER].text, "Opened"))
507  return 0;
508  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "Closed"))
509  return 1;
510  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "Opening"))
511  return 2;
512  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "Closing"))
513  return 3;
514  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "ShutterError"))
515  return 4;
516  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter module is not communicating to the azimuth module"))
517  return 5;
518  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 opposite direction timeout error on open occurred"))
519  return 6;
520  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 opposite direction timeout error on close occurred"))
521  return 7;
522  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 opposite direction timeout error on open occurred"))
523  return 8;
524  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 opposite direction timeout error on close occurred"))
525  return 9;
526  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 completion timeout error on open occurred"))
527  return 10;
528  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 completion timeout error on close occurred"))
529  return 11;
530  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 completion timeout error on open occurred"))
531  return 12;
532  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 completion timeout error on close occurred"))
533  return 13;
534  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 limit fault on open occurred"))
535  return 14;
536  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 limit fault on close occurred"))
537  return 15;
538  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 limit fault on open occurred"))
539  return 16;
540  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 limit fault on close occurred"))
541  return 17;
542  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "Shutter disabled (Shutter Enable input is not asserted)"))
543  return 18;
544  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "Intermediate"))
545  return 19;
546  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "GoTo"))
547  return 20;
548  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 OCP trip on open occurred"))
549  return 21;
550  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 1 OCP trip on close occurred"))
551  return 22;
552  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 OCP trip on open occurred"))
553  return 23;
554  else if (!strcmp(StatusT[STATUS_SHUTTER].text, "shutter 2 OCP trip on close occurred"))
555  return 24;
556  return 25;
557 }
558 
562 bool DomePro2::getFirmwareVersion()
563 {
564  char res[DRIVER_LEN] = {0};
565  if (sendCommand("DGfv", res) == false)
566  return false;
567 
568  int version = 0;
569  if (sscanf(res, "%X", &version) == 1)
570  {
571  char versionString[DRIVER_LEN] = {0};
572  snprintf(versionString, DRIVER_LEN, "%d", version);
573  IUSaveText(&VersionT[VERSION_FIRMWARE], versionString);
574  return true;
575  }
576 
577  return false;
578 }
579 
583 bool DomePro2::getHardwareConfig()
584 {
585  char res[DRIVER_LEN] = {0};
586  if (sendCommand("DGhc", res) == false)
587  return false;
588 
589  uint32_t config = 0;
590  if (sscanf(res, "%X", &config) == 1)
591  {
592  char configString[DRIVER_LEN] = {0};
593  uint8_t index = static_cast<uint8_t>(config);
594  if (DomeHardware.count(index))
595  {
596  snprintf(configString, DRIVER_LEN, "%s", DomeHardware.at(index).c_str());
597  IUSaveText(&VersionT[VERSION_HARDWARE], configString);
598 
599  }
600  else
601  {
602  LOGF_WARN("Unknown model detected %d", config);
603  }
604 
605  return true;
606  }
607 
608  return false;
609 }
610 
614 bool DomePro2::getDomeStatus()
615 {
616  char res[DRIVER_LEN] = {0};
617  if (sendCommand("DGam", res) == false)
618  return false;
619 
620  if (DomeStatus.count(res))
621  {
622  IUSaveText(&StatusT[STATUS_DOME], DomeStatus.at(res).c_str());
623  return true;
624  }
625  else
626  {
627  LOGF_WARN("Unknown dome status detected %d", res);
628  return false;
629  }
630 }
631 
635 bool DomePro2::getShutterStatus()
636 {
637  char res[DRIVER_LEN] = {0};
638  if (sendCommand("DGsx", res) == false)
639  return false;
640 
641  uint32_t status = 0;
642  if (sscanf(res, "%X", &status) == 1)
643  {
644  char statusString[DRIVER_LEN] = {0};
645  uint8_t index = static_cast<uint8_t>(status);
646  if (ShutterStatus.count(index))
647  {
648  snprintf(statusString, DRIVER_LEN, "%s", ShutterStatus.at(index).c_str());
649  IUSaveText(&StatusT[STATUS_SHUTTER], statusString);
650 
651  }
652  else
653  {
654  LOGF_WARN("Unknown shutter status detected %d", status);
655  }
656 
657  return true;
658  }
659 
660  return false;
661 }
662 
666 bool DomePro2::getDomeAzCPR()
667 {
668  char res[DRIVER_LEN] = {0};
669  if (sendCommand("DGcp", res) == false)
670  return false;
671 
672  uint32_t cpr = 0;
673  if (sscanf(res, "%X", &cpr) == 1)
674  {
675  SettingsN[SETTINGS_AZ_CPR].value = cpr;
676  return true;
677  }
678 
679  return false;
680 }
681 
685 bool DomePro2::setDomeAzCPR(uint32_t cpr)
686 {
687  char cmd[DRIVER_LEN] = {0};
688  if (cpr < 0x20 || cpr > 0x40000000)
689  {
690  LOG_ERROR("CPR value out of bounds (32 to 1,073,741,824)");
691  return false;
692  }
693  else if (cpr % 2 != 0)
694  {
695  LOG_ERROR("CPR value must be an even number");
696  return false;
697  }
698  snprintf(cmd, DRIVER_LEN, "DScp0x%08X", cpr);
699  if (sendCommand(cmd) == false)
700  return false;
701  return true;
702 }
703 
707 bool DomePro2::getDomeAzCoast()
708 {
709  char res[DRIVER_LEN] = {0};
710  if (sendCommand("DGco", res) == false)
711  return false;
712 
713  uint32_t coast = 0;
714  if (sscanf(res, "%X", &coast) == 1)
715  {
716  SettingsN[SETTINGS_AZ_COAST].value = coast * (360 / SettingsN[SETTINGS_AZ_CPR].value);
717  return true;
718  }
719 
720  return false;
721 }
722 
726 bool DomePro2::setDomeAzCoast(uint32_t az)
727 {
728  char cmd[DRIVER_LEN] = {0};
729  uint32_t steps = static_cast<uint32_t>(az * (SettingsN[SETTINGS_AZ_CPR].value / 360));
730  // if (coast > 0x4000)
731  // {
732  // LOG_ERROR("Coast value out of bounds (0 to 16,384)");
733  // return false;
734  // }
735  snprintf(cmd, DRIVER_LEN, "DSco0x%08X", steps);
736  if (sendCommand(cmd) == false)
737  return false;
738  return true;
739 }
740 
744 bool DomePro2::getDomeHomeAz()
745 {
746  char res[DRIVER_LEN] = {0};
747  if (sendCommand("DGha", res) == false)
748  return false;
749 
750  uint32_t home = 0;
751  if (sscanf(res, "%X", &home) == 1)
752  {
753  SettingsN[SETTINGS_AZ_HOME].value = home * (360 / SettingsN[SETTINGS_AZ_CPR].value);
754  return true;
755  }
756 
757  return false;
758 }
759 
763 bool DomePro2::setDomeHomeAz(uint32_t az)
764 {
765  char cmd[DRIVER_LEN] = {0};
766  uint32_t steps = static_cast<uint32_t>(az * (SettingsN[SETTINGS_AZ_CPR].value / 360));
767  // if (home >= SettingsN[SETTINGS_AZ_CPR].value)
768  // {
769  // char err[DRIVER_LEN] = {0};
770  // snprintf(err, DRIVER_LEN, "Home value out of bounds (0 to %.f, value has to be less than CPR)",
771  // SettingsN[SETTINGS_AZ_CPR].value - 1);
772  // LOG_ERROR(err);
773  // return false;
774  // }
775  snprintf(cmd, DRIVER_LEN, "DSha0x%08X", steps);
776  if (sendCommand(cmd) == false)
777  return false;
778  return true;
779 }
780 
784 bool DomePro2::getDomeParkAz()
785 {
786  char res[DRIVER_LEN] = {0};
787  if (sendCommand("DGpa", res) == false)
788  return false;
789 
790  uint32_t park = 0;
791  if (sscanf(res, "%X", &park) == 1)
792  {
793  SettingsN[SETTINGS_AZ_PARK].value = park * (360 / SettingsN[SETTINGS_AZ_CPR].value);
794  return true;
795  }
796 
797  return false;
798 }
799 
803 bool DomePro2::setDomeParkAz(uint32_t az)
804 {
805  char cmd[DRIVER_LEN] = {0};
806  uint32_t steps = static_cast<uint32_t>(az * (SettingsN[SETTINGS_AZ_CPR].value / 360));
807  // if (park >= SettingsN[SETTINGS_AZ_CPR].value)
808  // {
809  // char err[DRIVER_LEN] = {0};
810  // snprintf(err, DRIVER_LEN, "Park value out of bounds (0 to %.f, value has to be less than CPR)",
811  // SettingsN[SETTINGS_AZ_CPR].value - 1);
812  // LOG_ERROR(err);
813  // return false;
814  // }
815  snprintf(cmd, DRIVER_LEN, "DSpa0x%08X", steps);
816  if (sendCommand(cmd) == false)
817  return false;
818  return true;
819 }
820 
824 bool DomePro2::calibrateDomeAz(double az)
825 {
826  char cmd[DRIVER_LEN] = {0};
827  uint32_t steps = static_cast<uint32_t>(az * (SettingsN[SETTINGS_AZ_CPR].value / 360));
828  // if (steps >= SettingsN[SETTINGS_AZ_CPR].value)
829  // {
830  // char err[DRIVER_LEN] = {0};
831  // snprintf(err, DRIVER_LEN, "Degree value out of bounds");
832  // LOG_ERROR(err);
833  // return false;
834  // }
835  snprintf(cmd, DRIVER_LEN, "DSca0x%08X", steps);
836  if (sendCommand(cmd) == false)
837  return false;
838  return true;
839 }
840 
844 bool DomePro2::getDomeAzStallCount()
845 {
846  char res[DRIVER_LEN] = {0};
847  if (sendCommand("DGas", res) == false)
848  return false;
849 
850  uint32_t count = 0;
851  if (sscanf(res, "%X", &count) == 1)
852  {
853  SettingsN[SETTINGS_AZ_STALL_COUNT].value = count;
854  return true;
855  }
856 
857  return false;
858 }
859 
863 bool DomePro2::setDomeAzStallCount(uint32_t count)
864 {
865  char cmd[DRIVER_LEN] = {0};
866  snprintf(cmd, DRIVER_LEN, "DSha0x%08X", count);
867  if (sendCommand(cmd) == false)
868  return false;
869  return true;
870 }
871 
875 bool DomePro2::getDomeAzPos()
876 {
877  char res[DRIVER_LEN] = {0};
878  if (sendCommand("DGap", res) == false)
879  return false;
880 
881  uint32_t pos = 0;
882  if (sscanf(res, "%X", &pos) == 1)
883  {
884  DomeAbsPosN[0].value = pos * (360 / SettingsN[SETTINGS_AZ_CPR].value);
885  return true;
886  }
887 
888  return false;
889 }
890 
894 bool DomePro2::gotoDomeAz(uint32_t az)
895 {
896  char cmd[DRIVER_LEN] = {0};
897  if (az >= SettingsN[SETTINGS_AZ_CPR].value)
898  return false;
899  snprintf(cmd, DRIVER_LEN, "DSgo0x%08X", az);
900  if (sendCommand(cmd) == false)
901  return false;
902  return true;
903 }
904 
908 bool DomePro2::gotoDomePark()
909 {
910  if (sendCommand("DSgp") == false)
911  return false;
912  return true;
913 }
914 
918 bool DomePro2::killDomeAzMovement()
919 {
920  if (sendCommand("DXxa") == false)
921  return false;
922  return true;
923 }
924 
928 bool DomePro2::killDomeShutterMovement()
929 {
930  if (sendCommand("DXxs") == false)
931  return false;
932  return true;
933 }
934 
938 bool DomePro2::openDomeShutters()
939 {
940  if (sendCommand("DSso") == false)
941  return false;
942  return true;
943 }
944 
948 bool DomePro2::closeDomeShutters()
949 {
950  if (sendCommand("DSsc") == false)
951  return false;
952  return true;
953 }
954 
958 bool DomePro2::gotoHomeDomeAz()
959 {
960  if (sendCommand("DSah") == false)
961  return false;
962  return true;
963 }
964 
968 bool DomePro2::discoverHomeDomeAz()
969 {
970  if (sendCommand("DSdh") == false)
971  return false;
972  return true;
973 }
974 
978 bool DomePro2::setDomeLeftOn()
979 {
980  if (sendCommand("DSol") == false)
981  return false;
982  return true;
983 }
984 
988 bool DomePro2::setDomeRightOn()
989 {
990  if (sendCommand("DSor") == false)
991  return false;
992  return true;
993 }
994 
998 bool DomePro2::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
999 {
1000  int nbytes_written = 0, nbytes_read = 0, rc = -1;
1001 
1002  tcflush(PortFD, TCIOFLUSH);
1003 
1004  if (cmd_len > 0)
1005  {
1006  char hex_cmd[DRIVER_LEN * 3] = {0};
1007  hexDump(hex_cmd, cmd, cmd_len);
1008  LOGF_DEBUG("CMD <%s>", hex_cmd);
1009  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
1010  }
1011  else
1012  {
1013  LOGF_DEBUG("CMD <%s>", cmd);
1014 
1015  char formatted_command[DRIVER_LEN] = {0};
1016  snprintf(formatted_command, DRIVER_LEN, "!%s;", cmd);
1017  rc = tty_write_string(PortFD, formatted_command, &nbytes_written);
1018  }
1019 
1020  if (rc != TTY_OK)
1021  {
1022  char errstr[MAXRBUF] = {0};
1023  tty_error_msg(rc, errstr, MAXRBUF);
1024  LOGF_ERROR("Serial write error: %s.", errstr);
1025  return false;
1026  }
1027 
1028  if (res == nullptr)
1029  return true;
1030 
1031  if (res_len > 0)
1032  rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
1033  else
1034  rc = tty_nread_section(PortFD, res, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
1035 
1036  if (rc != TTY_OK)
1037  {
1038  char errstr[MAXRBUF] = {0};
1039  tty_error_msg(rc, errstr, MAXRBUF);
1040  LOGF_ERROR("Serial read error: %s.", errstr);
1041  return false;
1042  }
1043 
1044  if (res_len > 0)
1045  {
1046  char hex_res[DRIVER_LEN * 3] = {0};
1047  hexDump(hex_res, res, res_len);
1048  LOGF_DEBUG("RES <%s>", hex_res);
1049  }
1050  else
1051  {
1052  // Remove extra \r
1053  res[nbytes_read - 1] = 0;
1054  LOGF_DEBUG("RES <%s>", res);
1055  }
1056 
1057  tcflush(PortFD, TCIOFLUSH);
1058 
1059  return true;
1060 }
1061 
1065 void DomePro2::hexDump(char * buf, const char * data, int size)
1066 {
1067  for (int i = 0; i < size; i++)
1068  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
1069 
1070  if (size > 0)
1071  buf[3 * size - 1] = '\0';
1072 }
1073 
1077 std::vector<std::string> DomePro2::split(const std::string &input, const std::string &regex)
1078 {
1079  // passing -1 as the submatch index parameter performs splitting
1080  std::regex re(regex);
1081  std::sregex_token_iterator
1082  first{input.begin(), input.end(), re, -1},
1083  last;
1084  return {first, last};
1085 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
DomePro2()
Definition: domepro2.cpp:35
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: domepro2.cpp:291
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:421
virtual IPState ControlShutter(ShutterOperation operation) override
Open or Close shutter.
Definition: domepro2.cpp:429
virtual bool Sync(double az) override
Sync sets the dome current azimuth as the supplied azimuth position.
Definition: domepro2.cpp:374
virtual const char * getDefaultName() override
Definition: domepro2.cpp:125
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: domepro2.cpp:160
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: domepro2.cpp:485
virtual IPState MoveRel(double azDiff) override
Move the Dome to an relative position.
Definition: domepro2.cpp:358
virtual IPState MoveAbs(double az) override
Move the Dome to an absolute azimuth.
Definition: domepro2.cpp:346
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: domepro2.cpp:47
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: domepro2.cpp:494
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation) override
Move the Dome in a particular direction.
Definition: domepro2.cpp:385
virtual bool Handshake() override
perform handshake with device to check communication
Definition: domepro2.cpp:117
virtual bool Abort() override
Abort all dome motion.
Definition: domepro2.cpp:447
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
Definition: domepro2.cpp:475
virtual IPState Park() override
Goto Park Position. The park position is an absolute azimuth value.
Definition: domepro2.cpp:411
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: domepro2.cpp:214
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: domepro2.cpp:133
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
@ 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
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1633
void SetDomeCapability(uint32_t cap)
SetDomeCapability set the dome capabilities. All capabilities must be initialized.
Definition: indidome.cpp:1561
@ DOME_PARKING
Definition: indidome.h:134
@ DOME_MOVING
Definition: indidome.h:132
ShutterState m_ShutterState
Definition: indidome.h:624
void SetAxis1Park(double value)
SetRAPark Set current AZ parking position. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1861
INumber DomeAbsPosN[1]
Definition: indidome.h:534
void SetAxis1ParkDefault(double steps)
SetAxis1Park Set default AZ parking position.
Definition: indidome.cpp:1868
ShutterOperation
Shutter operation command.
Definition: indidome.h:114
@ SHUTTER_CLOSE
Definition: indidome.h:116
@ SHUTTER_OPEN
Definition: indidome.h:115
int PortFD
Definition: indidome.h:617
DomeMotionCommand
Definition: indidome.h:97
@ MOTION_STOP
Definition: indidome.h:99
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indidome.cpp:93
@ DOME_CCW
Definition: indidome.h:94
INumberVectorProperty DomeAbsPosNP
Definition: indidome.h:533
@ 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
ISwitchVectorProperty ParkSP
Definition: indidome.h:551
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indidome.cpp:279
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indidome.cpp:492
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
Definition: indidome.cpp:1043
void setShutterState(const ShutterState &value)
Definition: indidome.cpp:1119
void setDomeState(const DomeState &value)
Definition: indidome.cpp:1156
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Definition: indidome.cpp:1644
Connection::Serial * serialConnection
Definition: indidome.h:619
void SetParkDataType(DomeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
Definition: indidome.cpp:1587
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:390
DomeState getDomeState() const
Definition: indidome.h:285
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
double max(void)
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#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 MAXRBUF
Definition: indiserver.cpp:102
bool park(const int fd)
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250