Instrument Neutral Distributed Interface INDI  1.9.2
indidome.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  INDI Dome Base Class
3  Copyright(c) 2014 Jasem Mutlaq. All rights reserved.
4 
5  The code used calculate dome target AZ and ZD is written by Ferran Casarramona, and adapted from code from Markus Wildi.
6  The transformations are based on the paper Matrix Method for Coodinates Transformation written by Toshimi Taki (http://www.asahi-net.or.jp/~zs3t-tk).
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License version 2 as published by the Free Software Foundation.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 *******************************************************************************/
22 
23 #include "indidome.h"
24 
25 #include "indicom.h"
26 #include "indicontroller.h"
27 #include "inditimer.h"
30 
31 #include <libnova/julian_day.h>
32 #include <libnova/sidereal_time.h>
33 #include <libnova/transform.h>
34 
35 #include <cerrno>
36 #include <cmath>
37 #include <cstring>
38 #include <wordexp.h>
39 #include <pwd.h>
40 #include <unistd.h>
41 #include <limits>
42 
43 #define DOME_SLAVING_TAB "Slaving"
44 #define DOME_COORD_THRESHOLD \
45  0.1 /* Only send debug messages if the differences between old and new values of Az/Alt excceds this value */
46 
47 namespace INDI
48 {
49 
50 Dome::Dome() : ParkDataFileName(GetHomeDirectory() + "/.indi/ParkData.xml")
51 {
52  controller = new Controller(this);
53 
54  controller->setButtonCallback(buttonHelper);
55 
56  prev_az = prev_alt = prev_ra = prev_dec = 0;
59 
60  capability = 0;
61 
64 
66  ParkdataXmlRoot = nullptr;
67 
68  m_MountUpdateTimer.callOnTimeout(std::bind(&Dome::UpdateMountCoords, this));
69 }
70 
72 {
73  delXMLEle(ParkdataXmlRoot);
74 
75  delete controller;
76  delete serialConnection;
77  delete tcpConnection;
78 }
79 
80 std::string Dome::GetHomeDirectory() const
81 {
82  // Check first the HOME environmental variable
83  const char * HomeDir = getenv("HOME");
84 
85  // ...otherwise get the home directory of the current user.
86  if (!HomeDir)
87  {
88  HomeDir = getpwuid(getuid())->pw_dir;
89  }
90  return (HomeDir ? std::string(HomeDir) : "");
91 }
92 
94 {
95  DefaultDevice::initProperties(); // let the base class flesh in what it wants
96 
97  // Presets
98  IUFillNumber(&PresetN[0], "Preset 1", "", "%6.2f", 0, 360.0, 1.0, 0);
99  IUFillNumber(&PresetN[1], "Preset 2", "", "%6.2f", 0, 360.0, 1.0, 0);
100  IUFillNumber(&PresetN[2], "Preset 3", "", "%6.2f", 0, 360.0, 1.0, 0);
101  IUFillNumberVector(&PresetNP, PresetN, 3, getDeviceName(), "Presets", "", "Presets", IP_RW, 0, IPS_IDLE);
102 
103  //Preset GOTO
104  IUFillSwitch(&PresetGotoS[0], "Preset 1", "", ISS_OFF);
105  IUFillSwitch(&PresetGotoS[1], "Preset 2", "", ISS_OFF);
106  IUFillSwitch(&PresetGotoS[2], "Preset 3", "", ISS_OFF);
107  IUFillSwitchVector(&PresetGotoSP, PresetGotoS, 3, getDeviceName(), "Goto", "", "Presets", IP_RW, ISR_1OFMANY, 0,
108  IPS_IDLE);
109 
110  // IUFillSwitch(&AutoParkS[0], "INDI_ENABLED", "Enable", ISS_OFF);
111  // IUFillSwitch(&AutoParkS[1], "INDI_DISABLED", "Disable", ISS_ON);
112  // IUFillSwitchVector(&AutoParkSP, AutoParkS, 2, getDeviceName(), "DOME_AUTOPARK", "Auto Park", OPTIONS_TAB, IP_RW,
113  // ISR_1OFMANY, 0, IPS_IDLE);
114 
115  // Active Devices
116  IUFillText(&ActiveDeviceT[0], "ACTIVE_TELESCOPE", "Telescope", "Telescope Simulator");
117  //IUFillText(&ActiveDeviceT[1], "ACTIVE_WEATHER", "Weather", "WunderGround");
118  IUFillTextVector(&ActiveDeviceTP, ActiveDeviceT, 1, getDeviceName(), "ACTIVE_DEVICES", "Snoop devices", OPTIONS_TAB,
119  IP_RW, 60, IPS_IDLE);
120 
121  // Use locking if telescope is unparked
122  IUFillSwitch(&MountPolicyS[MOUNT_IGNORED], "MOUNT_IGNORED", "Mount ignored", ISS_ON);
123  IUFillSwitch(&MountPolicyS[MOUNT_LOCKS], "MOUNT_LOCKS", "Mount locks", ISS_OFF);
124  IUFillSwitchVector(&MountPolicySP, MountPolicyS, 2, getDeviceName(), "MOUNT_POLICY", "Mount Policy", OPTIONS_TAB, IP_RW,
125  ISR_1OFMANY, 60, IPS_IDLE);
126 
127  // Shutter Policy
128  IUFillSwitch(&ShutterParkPolicyS[SHUTTER_CLOSE_ON_PARK], "SHUTTER_CLOSE_ON_PARK", "Close On Park", ISS_OFF);
129  IUFillSwitch(&ShutterParkPolicyS[SHUTTER_OPEN_ON_UNPARK], "SHUTTER_OPEN_ON_UNPARK", "Open On UnPark", ISS_OFF);
130  IUFillSwitchVector(&ShutterParkPolicySP, ShutterParkPolicyS, 2, getDeviceName(), "DOME_SHUTTER_PARK_POLICY", "Shutter",
132 
133  // Measurements
134  IUFillNumber(&DomeMeasurementsN[DM_DOME_RADIUS], "DM_DOME_RADIUS", "Radius (m)", "%6.2f", 0.0, 50.0, 1.0, 0.0);
135  IUFillNumber(&DomeMeasurementsN[DM_SHUTTER_WIDTH], "DM_SHUTTER_WIDTH", "Shutter width (m)", "%6.2f", 0.0, 10.0, 1.0,
136  0.0);
137  IUFillNumber(&DomeMeasurementsN[DM_NORTH_DISPLACEMENT], "DM_NORTH_DISPLACEMENT", "N displacement (m)", "%6.2f",
138  -10.0, 10.0, 1.0, 0.0);
139  IUFillNumber(&DomeMeasurementsN[DM_EAST_DISPLACEMENT], "DM_EAST_DISPLACEMENT", "E displacement (m)", "%6.2f", -10.0,
140  10.0, 1.0, 0.0);
141  IUFillNumber(&DomeMeasurementsN[DM_UP_DISPLACEMENT], "DM_UP_DISPLACEMENT", "Up displacement (m)", "%6.2f", -10,
142  10.0, 1.0, 0.0);
143  IUFillNumber(&DomeMeasurementsN[DM_OTA_OFFSET], "DM_OTA_OFFSET", "OTA offset (m)", "%6.2f", -10.0, 10.0, 1.0, 0.0);
144  IUFillNumberVector(&DomeMeasurementsNP, DomeMeasurementsN, 6, getDeviceName(), "DOME_MEASUREMENTS", "Measurements",
146 
147  IUFillSwitch(&OTASideS[DM_OTA_SIDE_EAST], "DM_OTA_SIDE_EAST", "East", ISS_OFF);
148  IUFillSwitch(&OTASideS[DM_OTA_SIDE_WEST], "DM_OTA_SIDE_WEST", "West", ISS_OFF);
149  IUFillSwitch(&OTASideS[DM_OTA_SIDE_MOUNT], "DM_OTA_SIDE_MOUNT", "Mount", ISS_ON);
150  IUFillSwitch(&OTASideS[DM_OTA_SIDE_HA], "DM_OTA_SIDE_HA", "Hour Angle", ISS_OFF);
151  IUFillSwitch(&OTASideS[DM_OTA_SIDE_IGNORE], "DM_OTA_SIDE_IGNORE", "Ignore", ISS_OFF);
152  IUFillSwitchVector(&OTASideSP, OTASideS, 5, getDeviceName(), "DM_OTA_SIDE", "Meridian side", DOME_SLAVING_TAB,
153  IP_RW, ISR_ATMOST1, 60, IPS_OK);
154 
155  IUFillSwitch(&DomeAutoSyncS[0], "DOME_AUTOSYNC_ENABLE", "Enable", ISS_OFF);
156  IUFillSwitch(&DomeAutoSyncS[1], "DOME_AUTOSYNC_DISABLE", "Disable", ISS_ON);
158  IP_RW, ISR_1OFMANY, 60, IPS_OK);
159 
160  IUFillNumber(&DomeSpeedN[0], "DOME_SPEED_VALUE", "RPM", "%6.2f", 0.0, 10, 0.1, 1.0);
161  IUFillNumberVector(&DomeSpeedNP, DomeSpeedN, 1, getDeviceName(), "DOME_SPEED", "Speed", MAIN_CONTROL_TAB, IP_RW, 60,
162  IPS_OK);
163 
164  IUFillNumber(&DomeSyncN[0], "DOME_SYNC_VALUE", "Az", "%.2f", 0.0, 360, 10, 0.0);
165  IUFillNumberVector(&DomeSyncNP, DomeSyncN, 1, getDeviceName(), "DOME_SYNC", "Sync", MAIN_CONTROL_TAB, IP_RW, 60,
166  IPS_OK);
167 
168  IUFillSwitch(&DomeMotionS[0], "DOME_CW", "Dome CW", ISS_OFF);
169  IUFillSwitch(&DomeMotionS[1], "DOME_CCW", "Dome CCW", ISS_OFF);
171  ISR_ATMOST1, 60, IPS_OK);
172 
173  // Driver can define those to clients if there is support
174  IUFillNumber(&DomeAbsPosN[0], "DOME_ABSOLUTE_POSITION", "Degrees", "%6.2f", 0.0, 360.0, 1.0, 0.0);
175  IUFillNumberVector(&DomeAbsPosNP, DomeAbsPosN, 1, getDeviceName(), "ABS_DOME_POSITION", "Absolute Position",
177 
178  IUFillNumber(&DomeRelPosN[0], "DOME_RELATIVE_POSITION", "Degrees", "%6.2f", -180, 180.0, 10.0, 0.0);
179  IUFillNumberVector(&DomeRelPosNP, DomeRelPosN, 1, getDeviceName(), "REL_DOME_POSITION", "Relative Position",
181 
182  IUFillSwitch(&AbortS[0], "ABORT", "Abort", ISS_OFF);
183  IUFillSwitchVector(&AbortSP, AbortS, 1, getDeviceName(), "DOME_ABORT_MOTION", "Abort Motion", MAIN_CONTROL_TAB,
184  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
185 
186  IUFillNumber(&DomeParamN[0], "AUTOSYNC_THRESHOLD", "Autosync threshold (deg)", "%6.2f", 0.0, 360.0, 1.0, 0.5);
188  60, IPS_OK);
189 
190  IUFillSwitch(&ParkS[0], "PARK", "Park(ed)", ISS_OFF);
191  IUFillSwitch(&ParkS[1], "UNPARK", "UnPark(ed)", ISS_OFF);
193  60, IPS_OK);
194 
195  // Backlash Compensation
196  IUFillSwitch(&DomeBacklashS[INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
197  IUFillSwitch(&DomeBacklashS[INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_ON);
198  IUFillSwitchVector(&DomeBacklashSP, DomeBacklashS, 2, getDeviceName(), "DOME_BACKLASH_TOGGLE", "Backlash", OPTIONS_TAB,
199  IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
200 
201 
202  // Backlash Compensation Value
203  IUFillNumber(&DomeBacklashN[0], "DOME_BACKLASH_VALUE", "Steps", "%.f", 0, 1e6, 100, 0);
204  IUFillNumberVector(&DomeBacklashNP, DomeBacklashN, 1, getDeviceName(), "DOME_BACKLASH_STEPS", "Backlash",
205  OPTIONS_TAB, IP_RW, 60, IPS_OK);
206 
207 
208  IUFillSwitch(&DomeShutterS[0], "SHUTTER_OPEN", "Open", ISS_OFF);
209  IUFillSwitch(&DomeShutterS[1], "SHUTTER_CLOSE", "Close", ISS_ON);
210  IUFillSwitchVector(&DomeShutterSP, DomeShutterS, 2, getDeviceName(), "DOME_SHUTTER", "Shutter", MAIN_CONTROL_TAB,
211  IP_RW, ISR_ATMOST1, 60, IPS_OK);
212 
213  IUFillSwitch(&ParkOptionS[0], "PARK_CURRENT", "Current", ISS_OFF);
214  IUFillSwitch(&ParkOptionS[1], "PARK_DEFAULT", "Default", ISS_OFF);
215  IUFillSwitch(&ParkOptionS[2], "PARK_WRITE_DATA", "Write Data", ISS_OFF);
216  IUFillSwitchVector(&ParkOptionSP, ParkOptionS, 3, getDeviceName(), "DOME_PARK_OPTION", "Park Options", SITE_TAB,
217  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
218 
219  addDebugControl();
220 
221  controller->mapController("Dome CW", "CW/Open", Controller::CONTROLLER_BUTTON, "BUTTON_1");
222  controller->mapController("Dome CCW", "CCW/Close", Controller::CONTROLLER_BUTTON, "BUTTON_2");
223 
224  controller->initProperties();
225 
226  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_EOD_COORD");
227  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
228  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_PARK");
229  if (CanAbsMove())
230  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_PIER_SIDE");
231 
232  //IDSnoopDevice(ActiveDeviceT[1].text, "WEATHER_STATUS");
233 
235 
236  if (domeConnection & CONNECTION_SERIAL)
237  {
240  {
241  return callHandshake();
242  });
244  }
245 
246  if (domeConnection & CONNECTION_TCP)
247  {
248  tcpConnection = new Connection::TCP(this);
250  {
251  return callHandshake();
252  });
254  }
255 
256  return true;
257 }
258 
259 void Dome::ISGetProperties(const char * dev)
260 {
261  // First we let our parent populate
263 
265  loadConfig(true, "ACTIVE_DEVICES");
266 
267  ISState isMountIgnored = ISS_OFF;
268  if (IUGetConfigSwitch(getDeviceName(), MountPolicySP.name, MountPolicyS[MOUNT_IGNORED].name, &isMountIgnored) == 0)
269  {
270  MountPolicyS[MOUNT_IGNORED].s = isMountIgnored;
271  MountPolicyS[MOUNT_LOCKS].s = (isMountIgnored == ISS_ON) ? ISS_OFF : ISS_ON;
272  }
274 
275  controller->ISGetProperties(dev);
276  return;
277 }
278 
280 {
281  if (isConnected())
282  {
283  if (HasShutter())
284  {
287  }
288 
289  // Now we add our Dome specific stuff
291 
292  if (HasVariableSpeed())
293  {
295  }
296  if (CanRelMove())
298  if (CanAbsMove())
300  if (CanAbort())
302  if (CanAbsMove())
303  {
306 
311  }
312  if (CanSync())
314 
315  if (CanPark())
316  {
318  if (parkDataType != PARK_NONE)
319  {
322  }
323  }
324 
325  if (HasBacklash())
326  {
329  }
330 
331  //defineProperty(&AutoParkSP);
332  }
333  else
334  {
335  if (HasShutter())
336  {
339  }
340 
342 
343  if (HasVariableSpeed())
344  {
346  }
347  if (CanRelMove())
349  if (CanAbsMove())
351  if (CanAbort())
353  if (CanAbsMove())
354  {
357 
362  }
363 
364  if (CanSync())
366 
367  if (CanPark())
368  {
370  if (parkDataType != PARK_NONE)
371  {
374  }
375  }
376 
377  if (HasBacklash())
378  {
381  }
382 
383  //deleteProperty(AutoParkSP.name);
384  }
385 
386  controller->updateProperties();
387  return true;
388 }
389 
390 bool Dome::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
391 {
392  // first check if it's for our device
393  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
394  {
395  if (!strcmp(name, PresetNP.name))
396  {
397  IUUpdateNumber(&PresetNP, values, names, n);
398  PresetNP.s = IPS_OK;
399  IDSetNumber(&PresetNP, nullptr);
400 
401  return true;
402  }
403  // Dome Sync
404  else if (!strcmp(name, DomeSyncNP.name))
405  {
406  if (Sync(values[0]))
407  {
408  IUUpdateNumber(&DomeSyncNP, values, names, n);
409  DomeSyncNP.s = IPS_OK;
410  DomeAbsPosN[0].value = values[0];
411  IDSetNumber(&DomeAbsPosNP, nullptr);
412  }
413  else
414  {
416  }
417 
418  IDSetNumber(&DomeSyncNP, nullptr);
419  return true;
420  }
421  else if (!strcmp(name, DomeParamNP.name))
422  {
423  IUUpdateNumber(&DomeParamNP, values, names, n);
424  DomeParamNP.s = IPS_OK;
425  IDSetNumber(&DomeParamNP, nullptr);
426  return true;
427  }
428  else if (!strcmp(name, DomeSpeedNP.name))
429  {
430  double newSpeed = values[0];
431  Dome::SetSpeed(newSpeed);
432  return true;
433  }
434  else if (!strcmp(name, DomeAbsPosNP.name))
435  {
436  double newPos = values[0];
437  Dome::MoveAbs(newPos);
438  return true;
439  }
440  else if (!strcmp(name, DomeRelPosNP.name))
441  {
442  double newPos = values[0];
443  Dome::MoveRel(newPos);
444  return true;
445  }
446  else if (!strcmp(name, DomeMeasurementsNP.name))
447  {
448  IUUpdateNumber(&DomeMeasurementsNP, values, names, n);
450  IDSetNumber(&DomeMeasurementsNP, nullptr);
451 
452  return true;
453  }
454  else if (strcmp(name, ParkPositionNP.name) == 0)
455  {
456  IUUpdateNumber(&ParkPositionNP, values, names, n);
458 
459  Axis1ParkPosition = ParkPositionN[AXIS_RA].value;
460  IDSetNumber(&ParkPositionNP, nullptr);
461  return true;
462  }
464  // Backlash value
466  else if (!strcmp(name, DomeBacklashNP.name))
467  {
469  {
471  DEBUGDEVICE(dev, Logger::DBG_WARNING, "Dome backlash must be enabled first.");
472  }
473  else
474  {
475  uint32_t steps = static_cast<uint32_t>(values[0]);
476  if (SetBacklash(steps))
477  {
478  DomeBacklashN[0].value = values[0];
480  }
481  else
483  }
484  IDSetNumber(&DomeBacklashNP, nullptr);
485  return true;
486  }
487  }
488 
489  return DefaultDevice::ISNewNumber(dev, name, values, names, n);
490 }
491 
492 bool Dome::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
493 {
494  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
495  {
497  // GOTO Presets
499  if (!strcmp(PresetGotoSP.name, name))
500  {
501  if (m_DomeState == DOME_PARKED)
502  {
504  "Please unpark before issuing any motion commands.");
506  IDSetSwitch(&PresetGotoSP, nullptr);
507  return false;
508  }
509 
510  IUUpdateSwitch(&PresetGotoSP, states, names, n);
511  int index = IUFindOnSwitchIndex(&PresetGotoSP);
512  IPState rc = Dome::MoveAbs(PresetN[index].value);
513  if (rc == IPS_OK || rc == IPS_BUSY)
514  {
516  LOGF_INFO("Moving to Preset %d (%.2f degrees).", index + 1, PresetN[index].value);
517  IDSetSwitch(&PresetGotoSP, nullptr);
518  return true;
519  }
520 
522  IDSetSwitch(&PresetGotoSP, nullptr);
523  return false;
524  }
526  // Dome Auto Sync
528  else if (!strcmp(name, DomeAutoSyncSP.name))
529  {
530  IUUpdateSwitch(&DomeAutoSyncSP, states, names, n);
532 
533  if (DomeAutoSyncS[0].s == ISS_ON)
534  {
535  IDSetSwitch(&DomeAutoSyncSP, "Dome will now be synced to mount azimuth position.");
536  LOG_WARN("Dome will now be synced to mount azimuth position.");
537 
539  m_MountUpdateTimer.start(HORZ_UPDATE_TIMER);
540  }
541  else
542  {
543  IDSetSwitch(&DomeAutoSyncSP, "Dome is no longer synced to mount azimuth position.");
544  LOG_WARN("Dome is no longer synced to mount azimuth position.");
545  m_MountUpdateTimer.stop();
546 
547  if (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY /* || DomeTimerNP.s == IPS_BUSY*/)
548  Dome::Abort();
549  }
550 
551  return true;
552  }
554  // OTA Side
556  else if (!strcmp(name, OTASideSP.name))
557  {
558  IUUpdateSwitch(&OTASideSP, states, names, n);
559  OTASideSP.s = IPS_OK;
560 
561  if (OTASideS[DM_OTA_SIDE_EAST].s == ISS_ON)
562  {
563  LOG_WARN("Dome shall be synced assuming OTA situated east of the pier");
564  }
565  else if (OTASideS[DM_OTA_SIDE_WEST].s == ISS_ON)
566  {
567  LOG_WARN("Dome shall be synced assuming OTA situated west of the pier");
568  }
569  else if (OTASideS[DM_OTA_SIDE_MOUNT].s == ISS_ON)
570  {
571  LOG_WARN("Dome shall be synced from pier side as reported by the mount.");
572  }
573  else if (OTASideS[DM_OTA_SIDE_HA].s == ISS_ON)
574  {
575  LOG_WARN("Dome shall be synced for OTA pier side derived from Hour Angle.");
576  UpdateAutoSync();
577  }
578  else if (OTASideS[DM_OTA_SIDE_IGNORE].s == ISS_ON)
579  {
580  LOG_WARN("Dome shall be synced by ignoring pier side as in a fork mount.");
581  }
582 
583  UpdateAutoSync();
584  IDSetSwitch(&OTASideSP, nullptr);
585  return true;
586  }
588  // Dome Motion
590  else if (!strcmp(name, DomeMotionSP.name))
591  {
592  // Check if any switch is ON
593  for (int i = 0; i < n; i++)
594  {
595  if (states[i] == ISS_ON)
596  {
597  if (!strcmp(DomeMotionS[DOME_CW].name, names[i]))
599  else
601 
602  return true;
603  }
604  }
605 
606  // All switches are off, so let's turn off last motion
607  int current_direction = IUFindOnSwitchIndex(&DomeMotionSP);
608  // Shouldn't happen
609  if (current_direction < 0)
610  {
612  IDSetSwitch(&DomeMotionSP, nullptr);
613  return false;
614  }
615 
616  Dome::Move(static_cast<DomeDirection>(current_direction), MOTION_STOP);
617 
618  return true;
619  }
621  // Abort Motion
623  else if (!strcmp(name, AbortSP.name))
624  {
625  Dome::Abort();
626  return true;
627  }
629  // Shutter
631  else if (!strcmp(name, DomeShutterSP.name))
632  {
633  // Check if any switch is ON
634  for (int i = 0; i < n; i++)
635  {
636  if (states[i] == ISS_ON)
637  {
638  // Open
639  if (!strcmp(DomeShutterS[0].name, names[i]))
640  {
642  }
643  else
644  {
646  }
647  }
648  }
649  }
651  // Parking Switch
653  else if (!strcmp(name, ParkSP.name))
654  {
655  // Check if any switch is ON
656  for (int i = 0; i < n; i++)
657  {
658  if (states[i] == ISS_ON)
659  {
660  if (!strcmp(ParkS[0].name, names[i]))
661  {
662  if (m_DomeState == DOME_PARKING)
663  return false;
664 
665  return (Dome::Park() != IPS_ALERT);
666  }
667  else
668  {
670  return false;
671 
672  return (Dome::UnPark() != IPS_ALERT);
673  }
674  }
675  }
676  }
678  // Parking Option
680  else if (!strcmp(name, ParkOptionSP.name))
681  {
682  IUUpdateSwitch(&ParkOptionSP, states, names, n);
684  if (!sp)
685  return false;
686 
687  bool rc = false;
688 
690 
691  if (!strcmp(sp->name, "PARK_CURRENT"))
692  {
693  rc = SetCurrentPark();
694  }
695  else if (!strcmp(sp->name, "PARK_DEFAULT"))
696  {
697  rc = SetDefaultPark();
698  }
699  else if (!strcmp(sp->name, "PARK_WRITE_DATA"))
700  {
701  rc = WriteParkData();
702  if (rc)
703  DEBUG(Logger::DBG_SESSION, "Saved Park Status/Position.");
704  else
705  LOG_WARN( "Can not save Park Status/Position.");
706  }
707 
708  ParkOptionSP.s = rc ? IPS_OK : IPS_ALERT;
709  IDSetSwitch(&ParkOptionSP, nullptr);
710 
711  return true;
712  }
714  // Auto Park
716 #if 0
717  else if (!strcmp(name, AutoParkSP.name))
718  {
719  IUUpdateSwitch(&AutoParkSP, states, names, n);
720 
721  AutoParkSP.s = IPS_OK;
722 
723  if (AutoParkS[0].s == ISS_ON)
724  LOG_WARN( "Warning: Auto park is enabled. If weather conditions are in the "
725  "danger zone, the dome will be automatically parked. Only enable this "
726  "option is parking the dome at any time will not cause damage to any "
727  "equipment.");
728  else
729  DEBUG(Logger::DBG_SESSION, "Auto park is disabled.");
730 
731  IDSetSwitch(&AutoParkSP, nullptr);
732 
733  return true;
734  }
735 #endif
736  // Telescope Parking Policy
739  else if (!strcmp(name, MountPolicySP.name))
740  {
741  IUUpdateSwitch(&MountPolicySP, states, names, n);
744  LOG_INFO("Mount Policy set to: Mount ignored. Dome can park regardless of mount parking state.");
745  else
746  LOG_WARN("Mount Policy set to: Mount locks. This prevents the dome from parking when mount is unparked.");
747  IDSetSwitch(&MountPolicySP, nullptr);
748  triggerSnoop(ActiveDeviceT[0].text, "TELESCOPE_PARK");
749  return true;
750  }
752  // Shutter Parking Policy
754  else if (!strcmp(name, ShutterParkPolicySP.name))
755  {
756  IUUpdateSwitch(&ShutterParkPolicySP, states, names, n);
758  IDSetSwitch(&ShutterParkPolicySP, nullptr);
759  return true;
760  }
762  // Backlash enable/disable
764  else if (strcmp(name, DomeBacklashSP.name) == 0)
765  {
766  int prevIndex = IUFindOnSwitchIndex(&DomeBacklashSP);
767  IUUpdateSwitch(&DomeBacklashSP, states, names, n);
768  const bool enabled = IUFindOnSwitchIndex(&DomeBacklashSP) == INDI_ENABLED;
769 
770  if (SetBacklashEnabled(enabled))
771  {
772  IUUpdateSwitch(&DomeBacklashSP, states, names, n);
774  LOGF_INFO("Dome backlash is %s.", (enabled ? "enabled" : "disabled"));
775  }
776  else
777  {
779  DomeBacklashS[prevIndex].s = ISS_ON;
781  LOG_ERROR("Failed to set trigger Dome backlash.");
782  }
783 
784  IDSetSwitch(&DomeBacklashSP, nullptr);
785  return true;
786  }
787  }
788 
789  controller->ISNewSwitch(dev, name, states, names, n);
790 
791  // Nobody has claimed this, so, ignore it
792  return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
793 }
794 
795 bool Dome::ISNewText(const char * dev, const char * name, char * texts[], char * names[], int n)
796 {
797  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
798  {
799  if (strcmp(name, ActiveDeviceTP.name) == 0)
800  {
802  IUUpdateText(&ActiveDeviceTP, texts, names, n);
803  IDSetText(&ActiveDeviceTP, nullptr);
804 
805  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_EOD_COORD");
806  IDSnoopDevice(ActiveDeviceT[0].text, "TARGET_EOD_COORD");
807  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
808  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_PARK");
809  if (CanAbsMove())
810  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_PIER_SIDE");
811  //IDSnoopDevice(ActiveDeviceT[1].text, "WEATHER_STATUS");
812 
813  return true;
814  }
815  }
816 
817  controller->ISNewText(dev, name, texts, names, n);
818 
819  return DefaultDevice::ISNewText(dev, name, texts, names, n);
820 }
821 
823 {
824  XMLEle * ep = nullptr;
825  const char * propName = findXMLAttValu(root, "name");
826 
827  // Check TARGET
828  if (!strcmp("TARGET_EOD_COORD", propName))
829  {
830  int rc_ra = -1, rc_de = -1;
831  double ra = 0, de = 0;
832 
833  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
834  {
835  const char * elemName = findXMLAttValu(ep, "name");
836 
837  LOGF_DEBUG("Snooped Target RA-DEC: %s", pcdataXMLEle(ep));
838  if (!strcmp(elemName, "RA"))
839  rc_ra = f_scansexa(pcdataXMLEle(ep), &ra);
840  else if (!strcmp(elemName, "DEC"))
841  rc_de = f_scansexa(pcdataXMLEle(ep), &de);
842  }
843  // Dont start moving the dome till the mount has initialized all the variables
844  if (HaveRaDec && CanAbsMove())
845  {
846  if (rc_ra == 0 && rc_de == 0)
847  {
848  // everything parsed ok, so lets start the dome to moving
849  // If this slew involves a meridian flip, then the slaving calcs will end up using
850  // the wrong OTA side. Lets set things up so our slaving code will calculate the side
851  // for the target slew instead of using mount pier side info
852  // and see if we can get there at the same time as the mount
853  // TODO: see what happens in a meridian flip with OTASide
856  LOGF_DEBUG("Calling Update mount to anticipate goto target: %g - DEC: %g",
859  }
860  }
861 
862  return true;
863  }
864  // Check EOD
865  if (!strcmp("EQUATORIAL_EOD_COORD", propName))
866  {
867  int rc_ra = -1, rc_de = -1;
868  double ra = 0, de = 0;
869 
870  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
871  {
872  const char * elemName = findXMLAttValu(ep, "name");
873 
874  if (!strcmp(elemName, "RA"))
875  rc_ra = f_scansexa(pcdataXMLEle(ep), &ra);
876  else if (!strcmp(elemName, "DEC"))
877  rc_de = f_scansexa(pcdataXMLEle(ep), &de);
878  }
879 
880  if (rc_ra == 0 && rc_de == 0)
881  {
882  // Do not spam log
883  if (std::fabs(mountEquatorialCoords.rightascension - ra) > 0.01
884  || std::fabs(mountEquatorialCoords.declination - de) > 0.01)
885  {
886  char RAStr[64] = {0}, DEStr[64] = {0};
887  fs_sexa(RAStr, ra, 2, 3600);
888  fs_sexa(DEStr, de, 2, 3600);
889 
890  LOGF_DEBUG("Snooped RA %s DEC %s", RAStr, DEStr);
891  }
892 
895  }
896 
898  crackIPState(findXMLAttValu(root, "state"), &m_MountState);
899 
900  // If the diff > 0.1 then the mount is in motion, so let's wait until it settles before moving the doom
903  {
906  //LOGF_DEBUG("Snooped RA: %g - DEC: %g", mountEquatorialCoords.rightascension, mountEquatorialCoords.declination);
907  // a mount still initializing will emit 0 and 0 on the first go
908  // we dont want to process 0/0
910  HaveRaDec = true;
911  }
912  // else mount stable, i.e. tracking, so let's update mount coords and check if we need to move
913  else if (m_MountState == IPS_OK || m_MountState == IPS_IDLE)
915 
916  return true;
917  }
918 
919  // Check Geographic coords
920  if (!strcmp("GEOGRAPHIC_COORD", propName))
921  {
922  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
923  {
924  const char * elemName = findXMLAttValu(ep, "name");
925  if (!strcmp(elemName, "LONG"))
926  {
927  double indiLong;
928  f_scansexa(pcdataXMLEle(ep), &indiLong);
929  if (indiLong > 180)
930  indiLong -= 360;
931  observer.longitude = indiLong;
932  HaveLatLong = true;
933  }
934  else if (!strcmp(elemName, "LAT"))
936  }
937 
938  LOGF_DEBUG("Snooped LONG: %g - LAT: %g", observer.longitude, observer.latitude);
939 
941 
942  return true;
943  }
944 
945  // Check Telescope Park status
946  if (!strcmp("TELESCOPE_PARK", propName))
947  {
948  if (!strcmp(findXMLAttValu(root, "state"), "Ok"))
949  {
950  bool prevState = IsLocked;
951  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
952  {
953  const char * elemName = findXMLAttValu(ep, "name");
954 
955  if ((!strcmp(elemName, "PARK") && !strcmp(pcdataXMLEle(ep), "On")))
956  IsMountParked = true;
957  else if ((!strcmp(elemName, "UNPARK") && !strcmp(pcdataXMLEle(ep), "On")))
958  IsMountParked = false;
959 
960  if (IsLocked && !strcmp(elemName, "PARK") && !strcmp(pcdataXMLEle(ep), "On"))
961  IsLocked = false;
962  else if (!IsLocked && !strcmp(elemName, "UNPARK") && !strcmp(pcdataXMLEle(ep), "On"))
963  IsLocked = true;
964  }
965  if (prevState != IsLocked && MountPolicyS[1].s == ISS_ON)
966  LOGF_INFO("Telescope status changed. Lock is set to: %s",
967  IsLocked ? "locked" : "unlocked");
968  }
969  return true;
970  }
971 
972  // Weather Status
973  // JM 2020-07-16: Weather handling moved to Watchdog driver
974 #if 0
975  if (!strcmp("WEATHER_STATUS", propName))
976  {
977  weatherState = IPS_ALERT;
978  crackIPState(findXMLAttValu(root, "state"), &weatherState);
979 
980  if (weatherState == IPS_ALERT)
981  {
982  if (CanPark())
983  {
984  if (!isParked())
985  {
986  if (AutoParkS[0].s == ISS_ON)
987  {
988  LOG_WARN("Weather conditions in the danger zone! Parking dome...");
989  Dome::Park();
990  }
991  else
992  {
993  LOG_WARN("Weather conditions in the danger zone! AutoPark is disabled. Please park the dome!");
994  }
995  }
996  }
997  else
998  LOG_WARN("Weather conditions in the danger zone! Close the dome immediately!");
999 
1000  return true;
1001  }
1002  }
1003 #endif
1004  if (!strcmp("TELESCOPE_PIER_SIDE", propName))
1005  {
1006  // crack the message
1007  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
1008  {
1009  const char * elemName = findXMLAttValu(ep, "name");
1010 
1011  if (!strcmp(elemName, "PIER_EAST") && !strcmp(pcdataXMLEle(ep), "On"))
1012  mountOTASide = -1;
1013  else if (!strcmp(elemName, "PIER_WEST") && !strcmp(pcdataXMLEle(ep), "On"))
1014  mountOTASide = 1;
1015  }
1016 
1017  return true;
1018  }
1019 
1020  controller->ISSnoopDevice(root);
1021 
1022  return DefaultDevice::ISSnoopDevice(root);
1023 }
1024 
1025 bool Dome::SetBacklash(int32_t steps)
1026 {
1027  INDI_UNUSED(steps);
1028  LOG_ERROR("Dome does not support backlash compensation.");
1029  return false;
1030 }
1031 
1032 bool Dome::SetBacklashEnabled(bool enabled)
1033 {
1034  // If disabled, set the Domeer backlash to zero.
1035  if (enabled)
1036  return SetBacklash(static_cast<int32_t>(DomeBacklashN[0].value));
1037  else
1038  return SetBacklash(0);
1039 }
1040 
1041 bool Dome::saveConfigItems(FILE * fp)
1042 {
1044 
1052 
1053  if (HasBacklash())
1054  {
1057  }
1058 
1059  if (HasShutter())
1060  {
1062  }
1063 
1064  controller->saveConfigItems(fp);
1065 
1066  return true;
1067 }
1068 
1069 void Dome::triggerSnoop(const char * driverName, const char * snoopedProp)
1070 {
1071  LOGF_DEBUG("Active Snoop, driver: %s, property: %s", driverName, snoopedProp);
1072  IDSnoopDevice(driverName, snoopedProp);
1073 }
1074 
1076 {
1077  return MountPolicyS[1].s == ISS_ON && IsLocked;
1078 }
1079 
1080 void Dome::buttonHelper(const char * button_n, ISState state, void * context)
1081 {
1082  static_cast<Dome *>(context)->processButton(button_n, state);
1083 }
1084 
1085 void Dome::processButton(const char * button_n, ISState state)
1086 {
1087  //ignore OFF
1088  if (state == ISS_OFF)
1089  return;
1090 
1091  // Dome In
1092  if (!strcmp(button_n, "Dome CW"))
1093  {
1094  if (DomeMotionSP.s != IPS_BUSY)
1096  else
1098  }
1099  else if (!strcmp(button_n, "Dome CCW"))
1100  {
1101  if (DomeMotionSP.s != IPS_BUSY)
1103  else
1105  }
1106  else if (!strcmp(button_n, "Dome Abort"))
1107  {
1108  Dome::Abort();
1109  }
1110 }
1111 
1113 {
1114  return m_MountState;
1115 }
1116 
1118 {
1119  switch (value)
1120  {
1121  case SHUTTER_OPENED:
1125  break;
1126 
1127  case SHUTTER_CLOSED:
1131  break;
1132 
1133 
1134  case SHUTTER_MOVING:
1136  break;
1137 
1138  case SHUTTER_ERROR:
1140  LOG_WARN("Shutter failure.");
1141  break;
1142 
1143  case SHUTTER_UNKNOWN:
1146  LOG_WARN("Unknown shutter status.");
1147  break;
1148  }
1149 
1150  IDSetSwitch(&DomeShutterSP, nullptr);
1151  m_ShutterState = value;
1152 }
1153 
1155 {
1156  switch (value)
1157  {
1158  case DOME_IDLE:
1159  if (DomeMotionSP.s == IPS_BUSY)
1160  {
1163  IDSetSwitch(&DomeMotionSP, nullptr);
1164  }
1165  if (DomeAbsPosNP.s == IPS_BUSY)
1166  {
1168  IDSetNumber(&DomeAbsPosNP, nullptr);
1169  }
1170  if (DomeRelPosNP.s == IPS_BUSY)
1171  {
1173  IDSetNumber(&DomeRelPosNP, nullptr);
1174  }
1175  break;
1176 
1177  case DOME_SYNCED:
1178  if (DomeMotionSP.s == IPS_BUSY)
1179  {
1181  DomeMotionSP.s = IPS_OK;
1182  IDSetSwitch(&DomeMotionSP, nullptr);
1183  }
1184  if (DomeAbsPosNP.s == IPS_BUSY)
1185  {
1186  DomeAbsPosNP.s = IPS_OK;
1187  IDSetNumber(&DomeAbsPosNP, nullptr);
1188  }
1189  if (DomeRelPosNP.s == IPS_BUSY)
1190  {
1191  DomeRelPosNP.s = IPS_OK;
1192  IDSetNumber(&DomeRelPosNP, nullptr);
1193  }
1194  break;
1195 
1196  case DOME_PARKED:
1197  if (DomeMotionSP.s == IPS_BUSY)
1198  {
1201  IDSetSwitch(&DomeMotionSP, nullptr);
1202  }
1203  if (DomeAbsPosNP.s == IPS_BUSY)
1204  {
1206  IDSetNumber(&DomeAbsPosNP, nullptr);
1207  }
1208  if (DomeRelPosNP.s == IPS_BUSY)
1209  {
1211  IDSetNumber(&DomeRelPosNP, nullptr);
1212  }
1214  ParkSP.s = IPS_OK;
1215  ParkS[0].s = ISS_ON;
1216  IDSetSwitch(&ParkSP, nullptr);
1217  IsParked = true;
1218  break;
1219 
1220  case DOME_PARKING:
1222  ParkSP.s = IPS_BUSY;
1223  ParkS[0].s = ISS_ON;
1224  IDSetSwitch(&ParkSP, nullptr);
1225  break;
1226 
1227  case DOME_UNPARKING:
1229  ParkSP.s = IPS_BUSY;
1230  ParkS[1].s = ISS_ON;
1231  IDSetSwitch(&ParkSP, nullptr);
1232  break;
1233 
1234  case DOME_UNPARKED:
1236  ParkSP.s = IPS_OK;
1237  ParkS[1].s = ISS_ON;
1238  IDSetSwitch(&ParkSP, nullptr);
1239  IsParked = false;
1240  break;
1241 
1242  case DOME_UNKNOWN:
1244  ParkSP.s = IPS_IDLE;
1245  IsParked = false;
1246  IDSetSwitch(&ParkSP, nullptr);
1247  break;
1248 
1249  case DOME_ERROR:
1250  ParkSP.s = IPS_ALERT;
1251  IDSetSwitch(&ParkSP, nullptr);
1252  break;
1253 
1254  case DOME_MOVING:
1255  break;
1256  }
1257 
1258  m_DomeState = value;
1259 }
1260 
1261 /*
1262 The problem to get a dome azimuth given a telescope azimuth, altitude and geometry (telescope placement, mount geometry) can be seen as solve the intersection between the optical axis with the dome, that is, the intersection between a line and a sphere.
1263 To do that we need to calculate the optical axis line taking the centre of the dome as origin of coordinates.
1264 */
1265 
1266 // Returns false if it can't solve it due bad geometry of the observatory
1267 // Returns:
1268 // Az : Azimuth required to the dome in order to center the shutter aperture with telescope
1269 // minAz: Minimum azimuth in order to avoid any dome interference to the full aperture of the telescope
1270 // maxAz: Maximum azimuth in order to avoid any dome interference to the full aperture of the telescope
1271 bool Dome::GetTargetAz(double &Az, double &Alt, double &minAz, double &maxAz)
1272 {
1273  point3D MountCenter, OptCenter, OptVector, DomeIntersect;
1274  double hourAngle;
1275  double mu1, mu2;
1276 
1277  if (HaveLatLong == false)
1278  {
1279  triggerSnoop(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
1280  LOG_WARN( "Geographic coordinates are not yet defined, triggering snoop...");
1281  return false;
1282  }
1283 
1284  double JD = ln_get_julian_from_sys();
1285  double MSD = ln_get_mean_sidereal_time(JD);
1286 
1287  LOGF_DEBUG("JD: %g - MSD: %g", JD, MSD);
1288 
1289  MountCenter.x = DomeMeasurementsN[DM_EAST_DISPLACEMENT].value; // Positive to East
1290  MountCenter.y = DomeMeasurementsN[DM_NORTH_DISPLACEMENT].value; // Positive to North
1291  MountCenter.z = DomeMeasurementsN[DM_UP_DISPLACEMENT].value; // Positive Up
1292 
1293  LOGF_DEBUG("MC.x: %g - MC.y: %g MC.z: %g", MountCenter.x, MountCenter.y, MountCenter.z);
1294 
1295  // Get hour angle in hours
1296  hourAngle = rangeHA( MSD + observer.longitude / 15.0 - mountEquatorialCoords.rightascension);
1297 
1298  LOGF_DEBUG("HA: %g Lng: %g RA: %g", hourAngle, observer.longitude, mountEquatorialCoords.rightascension);
1299 
1300  int OTASide = 0; // Side of the telescope with respect of the mount, 1: west, -1: east, 0: use the mid point
1301 
1302  if (OTASideSP.s == IPS_OK)
1303  {
1304  if(OTASideS[DM_OTA_SIDE_EAST].s == ISS_ON)
1305  OTASide = -1;
1306  else if(OTASideS[DM_OTA_SIDE_WEST].s == ISS_ON)
1307  OTASide = 1;
1308  else if(OTASideS[DM_OTA_SIDE_MOUNT].s == ISS_ON)
1309  OTASide = mountOTASide;
1310  else if(OTASideS[DM_OTA_SIDE_HA].s == ISS_ON)
1311  {
1312  // Note if the telescope points West, OTA is at east of the pier, and viceversa.
1313  if(hourAngle > 0)
1314  OTASide = -1;
1315  else
1316  OTASide = 1;
1317  }
1318  LOGF_DEBUG("OTA_SIDE selection: %d", IUFindOnSwitchIndex(&OTASideSP));
1319  }
1320 
1321  OpticalCenter(MountCenter, OTASide * DomeMeasurementsN[DM_OTA_OFFSET].value, observer.latitude, hourAngle, OptCenter);
1322 
1323  LOGF_DEBUG("OTA_SIDE: %d", OTASide);
1324  LOGF_DEBUG("Mount OTA_SIDE: %d", mountOTASide);
1325  LOGF_DEBUG("OTA_OFFSET: %g Lat: %g", DomeMeasurementsN[DM_OTA_OFFSET].value, observer.latitude);
1326  LOGF_DEBUG("OC.x: %g - OC.y: %g OC.z: %g", OptCenter.x, OptCenter.y, OptCenter.z);
1327 
1328  // To be sure mountHoriztonalCoords is up to date.
1330 
1331  // Get optical axis point. This and the previous form the optical axis line
1334  LOGF_DEBUG("OV.x: %g - OV.y: %g OV.z: %g", OptVector.x, OptVector.y, OptVector.z);
1335 
1336  if (Intersection(OptCenter, OptVector, DomeMeasurementsN[DM_DOME_RADIUS].value, mu1, mu2))
1337  {
1338  // If telescope is pointing over the horizon, the solution is mu1, else is mu2
1339  if (mu1 < 0)
1340  mu1 = mu2;
1341 
1342  double yx;
1343  double HalfApertureChordAngle;
1344  double RadiusAtAlt;
1345 
1346  DomeIntersect.x = OptCenter.x + mu1 * (OptVector.x );
1347  DomeIntersect.y = OptCenter.y + mu1 * (OptVector.y );
1348  DomeIntersect.z = OptCenter.z + mu1 * (OptVector.z );
1349 
1350  if (fabs(DomeIntersect.x) > 0.00001)
1351  {
1352  yx = DomeIntersect.y / DomeIntersect.x;
1353  Az = 90 - 180 * atan(yx) / M_PI;
1354  if (DomeIntersect.x < 0)
1355  {
1356  Az = Az + 180;
1357  }
1358  if (Az >= 360)
1359  Az -= 360;
1360  else if (Az < 0)
1361  Az += 360;
1362  }
1363  else
1364  {
1365  // Dome East-West line or zenith
1366  if (DomeIntersect.y > 0)
1367  Az = 90;
1368  else
1369  Az = 270;
1370  }
1371 
1372  if ((fabs(DomeIntersect.x) > 0.00001) || (fabs(DomeIntersect.y) > 0.00001))
1373  Alt = 180 *
1374  atan(DomeIntersect.z /
1375  sqrt((DomeIntersect.x * DomeIntersect.x) + (DomeIntersect.y * DomeIntersect.y))) /
1376  M_PI;
1377  else
1378  Alt = 90; // Dome Zenith
1379 
1380  // Calculate the Azimuth range in the given Altitude of the dome
1381  RadiusAtAlt = DomeMeasurementsN[DM_DOME_RADIUS].value * cos(M_PI * Alt / 180); // Radius alt the given altitude
1382 
1383  if (DomeMeasurementsN[DM_SHUTTER_WIDTH].value < (2 * RadiusAtAlt))
1384  {
1385  HalfApertureChordAngle = 180 * asin(DomeMeasurementsN[DM_SHUTTER_WIDTH].value / (2 * RadiusAtAlt)) /
1386  M_PI; // Angle of a chord of half aperture length
1387  minAz = Az - HalfApertureChordAngle;
1388  if (minAz < 0)
1389  minAz = minAz + 360;
1390  maxAz = Az + HalfApertureChordAngle;
1391  if (maxAz >= 360)
1392  maxAz = maxAz - 360;
1393  }
1394  else
1395  {
1396  minAz = 0;
1397  maxAz = 360;
1398  }
1399  return true;
1400  }
1401 
1402  return false;
1403 }
1404 
1405 bool Dome::Intersection(point3D p1, point3D dp, double r, double &mu1, double &mu2)
1406 {
1407  double a, b, c;
1408  double bb4ac;
1409 
1410  a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
1411  b = 2 * (dp.x * p1.x + dp.y * p1.y + dp.z * p1.z);
1412  c = 0.0;
1413  c = c + p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
1414  c = c - r * r;
1415  bb4ac = b * b - 4 * a * c;
1416  if ((fabs(a) < 0.0000001) || (bb4ac < 0))
1417  {
1418  mu1 = 0;
1419  mu2 = 0;
1420  return false;
1421  }
1422 
1423  mu1 = (-b + sqrt(bb4ac)) / (2 * a);
1424  mu2 = (-b - sqrt(bb4ac)) / (2 * a);
1425 
1426  return true;
1427 }
1428 
1429 bool Dome::OpticalCenter(point3D MountCenter, double dOpticalAxis, double Lat, double Ah, point3D &OP)
1430 {
1431  double q, f;
1432  double cosf, sinf, cosq, sinq;
1433 
1434  // Note: this transformation is a circle rotated around X axis -(90 - Lat) degrees
1435  q = M_PI * (90 - Lat) / 180;
1436  f = -M_PI * (180 + Ah * 15) / 180;
1437 
1438  cosf = cos(f);
1439  sinf = sin(f);
1440  cosq = cos(q);
1441  sinq = sin(q);
1442 
1443  OP.x = (dOpticalAxis * cosf + MountCenter.x); // The sign of dOpticalAxis determines de side of the tube
1444  OP.y = (dOpticalAxis * sinf * cosq + MountCenter.y);
1445  OP.z = (dOpticalAxis * sinf * sinq + MountCenter.z);
1446 
1447  return true;
1448 }
1449 
1450 bool Dome::OpticalVector(double Az, double Alt, point3D &OV)
1451 {
1452  double q, f;
1453 
1454  q = M_PI * Alt / 180;
1455  f = M_PI * Az / 180;
1456  OV.x = cos(q) * sin(f);
1457  OV.y = cos(q) * cos(f);
1458  OV.z = sin(q);
1459 
1460  return true;
1461 }
1462 
1463 double Dome::Csc(double x)
1464 {
1465  return 1.0 / sin(x);
1466 }
1467 
1468 double Dome::Sec(double x)
1469 {
1470  return 1.0 / cos(x);
1471 }
1472 
1473 bool Dome::CheckHorizon(double HA, double dec, double lat)
1474 {
1475  double sinh_value;
1476 
1477  sinh_value = cos(lat) * cos(HA) * cos(dec) + sin(lat) * sin(dec);
1478 
1479  if (sinh_value >= 0.0)
1480  return true;
1481 
1482  return false;
1483 }
1484 
1486 {
1487  // If not initialized yet, return.
1489  return;
1490 
1491  // Dont do this if we haven't had co-ordinates from the mount yet
1492  if (!HaveLatLong)
1493  return;
1494  if (!HaveRaDec)
1495  return;
1496 
1498 
1499  // Control debug flooding
1502  {
1505  LOGF_DEBUG("Updated telescope Az: %g - Alt: %g", prev_az, prev_alt);
1506  }
1507 
1508  // Check if we need to move if mount is unparked.
1509  if (IsMountParked == false)
1510  UpdateAutoSync();
1511 }
1512 
1514 {
1516  {
1517  if (CanPark())
1518  {
1519  if (isParked() == true)
1520  {
1521  if (AutoSyncWarning == false)
1522  {
1523  LOG_WARN("Cannot perform autosync with dome parked. Please unpark to enable autosync operation.");
1524  AutoSyncWarning = true;
1525  }
1526  return;
1527  }
1528  }
1529 
1530  AutoSyncWarning = false;
1531  double targetAz = 0, targetAlt = 0, minAz = 0, maxAz = 0;
1532  bool res;
1533  res = GetTargetAz(targetAz, targetAlt, minAz, maxAz);
1534  if (!res)
1535  {
1536  LOGF_DEBUG("GetTargetAz failed %g", targetAz);
1537  return;
1538  }
1539  LOGF_DEBUG("Calculated target azimuth is %.2f. MinAz: %.2f, MaxAz: %.2f", targetAz, minAz,
1540  maxAz);
1541 
1542  if (fabs(targetAz - DomeAbsPosN[0].value) > DomeParamN[0].value)
1543  {
1544  IPState ret = Dome::MoveAbs(targetAz);
1545  if (ret == IPS_OK)
1546  LOGF_DEBUG("Dome synced to position %.2f degrees.", targetAz);
1547  else if (ret == IPS_BUSY)
1548  LOGF_DEBUG("Dome is syncing to position %.2f degrees...", targetAz);
1549  else
1550  LOG_ERROR("Dome failed to sync to new requested position.");
1551 
1552  DomeAbsPosNP.s = ret;
1553  IDSetNumber(&DomeAbsPosNP, nullptr);
1554  }
1555  }
1556 }
1557 
1558 void Dome::SetDomeCapability(uint32_t cap)
1559 {
1560  capability = cap;
1561 
1562  if (CanAbort())
1563  controller->mapController("Dome Abort", "Dome Abort", Controller::CONTROLLER_BUTTON, "BUTTON_3");
1564 }
1565 
1567 {
1568  switch (status)
1569  {
1570  case SHUTTER_OPENED:
1571  return "Shutter is open.";
1572  case SHUTTER_CLOSED:
1573  return "Shutter is closed.";
1574  case SHUTTER_MOVING:
1575  return "Shutter is moving.";
1576  case SHUTTER_ERROR:
1577  return "Shutter has errors.";
1578  case SHUTTER_UNKNOWN:
1579  default:
1580  return "Shutter status is unknown.";
1581  }
1582 }
1583 
1585 {
1586  parkDataType = type;
1587 
1588  switch (parkDataType)
1589  {
1590  case PARK_NONE:
1591  strncpy(DomeMotionS[DOME_CW].label, "Open", MAXINDILABEL);
1592  strncpy(DomeMotionS[DOME_CCW].label, "Close", MAXINDILABEL);
1593  break;
1594 
1595  case PARK_AZ:
1596  IUFillNumber(&ParkPositionN[AXIS_AZ], "PARK_AZ", "AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0);
1597  IUFillNumberVector(&ParkPositionNP, ParkPositionN, 1, getDeviceName(), "DOME_PARK_POSITION", "Park Position",
1598  SITE_TAB, IP_RW, 60, IPS_IDLE);
1599  break;
1600 
1601  case PARK_AZ_ENCODER:
1602  IUFillNumber(&ParkPositionN[AXIS_AZ], "PARK_AZ", "AZ Encoder", "%.0f", 0, 16777215, 1, 0);
1603  IUFillNumberVector(&ParkPositionNP, ParkPositionN, 1, getDeviceName(), "DOME_PARK_POSITION", "Park Position",
1604  SITE_TAB, IP_RW, 60, IPS_IDLE);
1605  break;
1606 
1607  default:
1608  break;
1609  }
1610 }
1611 
1612 void Dome::SyncParkStatus(bool isparked)
1613 {
1614  IsParked = isparked;
1615 
1617 
1618  if (IsParked)
1619  {
1621  DEBUG(Logger::DBG_SESSION, "Dome is parked.");
1622  }
1623  else
1624  {
1626  DEBUG(Logger::DBG_SESSION, "Dome is unparked.");
1627  }
1628 }
1629 
1630 void Dome::SetParked(bool isparked)
1631 {
1632  SyncParkStatus(isparked);
1633  WriteParkData();
1634 }
1635 
1637 {
1638  return IsParked;
1639 }
1640 
1642 {
1643  const char * loadres = LoadParkData();
1644  if (loadres)
1645  {
1646  LOGF_INFO("InitPark: No Park data in file %s: %s", ParkDataFileName.c_str(), loadres);
1647  SyncParkStatus(false);
1648  return false;
1649  }
1650 
1651  SyncParkStatus(isParked());
1652 
1653  if (parkDataType != PARK_NONE)
1654  {
1655  LOGF_DEBUG("InitPark Axis1 %.2f", Axis1ParkPosition);
1656  ParkPositionN[AXIS_AZ].value = Axis1ParkPosition;
1657  IDSetNumber(&ParkPositionNP, nullptr);
1658 
1659  // If parked, store the position as current azimuth angle or encoder ticks
1660  if (isParked() && CanAbsMove())
1661  {
1662  DomeAbsPosN[0].value = ParkPositionN[AXIS_AZ].value;
1663  IDSetNumber(&DomeAbsPosNP, nullptr);
1664  }
1665  }
1666 
1667  return true;
1668 }
1669 
1670 const char * Dome::LoadParkXML()
1671 {
1672  wordexp_t wexp;
1673  FILE * fp;
1674  LilXML * lp;
1675  static char errmsg[512];
1676 
1677  XMLEle * parkxml;
1678  XMLAtt * ap;
1679  bool devicefound = false;
1680 
1681  ParkDeviceName = getDeviceName();
1682  ParkstatusXml = nullptr;
1683  ParkdeviceXml = nullptr;
1684  ParkpositionXml = nullptr;
1685  ParkpositionAxis1Xml = nullptr;
1686 
1687  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
1688  {
1689  wordfree(&wexp);
1690  return "Badly formed filename.";
1691  }
1692 
1693  if (!(fp = fopen(wexp.we_wordv[0], "r")))
1694  {
1695  wordfree(&wexp);
1696  return strerror(errno);
1697  }
1698  wordfree(&wexp);
1699 
1700  lp = newLilXML();
1701 
1702  if (ParkdataXmlRoot)
1703  delXMLEle(ParkdataXmlRoot);
1704 
1705  ParkdataXmlRoot = readXMLFile(fp, lp, errmsg);
1706  fclose(fp);
1707 
1708  delLilXML(lp);
1709  if (!ParkdataXmlRoot)
1710  return errmsg;
1711 
1712  if (!strcmp(tagXMLEle(nextXMLEle(ParkdataXmlRoot, 1)), "parkdata"))
1713  return "Not a park data file";
1714 
1715  parkxml = nextXMLEle(ParkdataXmlRoot, 1);
1716 
1717  while (parkxml)
1718  {
1719  if (strcmp(tagXMLEle(parkxml), "device"))
1720  {
1721  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
1722  continue;
1723  }
1724  ap = findXMLAtt(parkxml, "name");
1725  if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName)))
1726  {
1727  devicefound = true;
1728  break;
1729  }
1730  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
1731  }
1732 
1733  if (!devicefound)
1734  return "No park data found for this device";
1735 
1736  ParkdeviceXml = parkxml;
1737  ParkstatusXml = findXMLEle(parkxml, "parkstatus");
1738 
1739  if (parkDataType != PARK_NONE)
1740  {
1741  ParkpositionXml = findXMLEle(parkxml, "parkposition");
1742  ParkpositionAxis1Xml = findXMLEle(ParkpositionXml, "axis1position");
1743 
1744  if (ParkpositionAxis1Xml == nullptr)
1745  {
1746  return "Park position invalid or missing.";
1747  }
1748  }
1749  else if (ParkstatusXml == nullptr)
1750  return "Park status invalid or missing.";
1751 
1752  return nullptr;
1753 }
1754 
1755 const char * Dome::LoadParkData()
1756 {
1757  IsParked = false;
1758 
1759  const char * result = LoadParkXML();
1760  if (result != nullptr)
1761  return result;
1762 
1763  if (!strcmp(pcdataXMLEle(ParkstatusXml), "true"))
1764  IsParked = true;
1765 
1766  if (parkDataType == PARK_NONE)
1767  return nullptr;
1768 
1769  double axis1Pos = std::numeric_limits<double>::quiet_NaN();
1770 
1771  int rc = sscanf(pcdataXMLEle(ParkpositionAxis1Xml), "%lf", &axis1Pos);
1772  if (rc != 1)
1773  {
1774  return "Unable to parse Park Position Axis 1.";
1775  }
1776 
1777  if (std::isnan(axis1Pos) == false)
1778  {
1779  Axis1ParkPosition = axis1Pos;
1780  return nullptr;
1781  }
1782 
1783  return "Failed to parse Park Position.";
1784 }
1785 
1787 {
1788  // We need to refresh parking data in case other devices parking states were updated since we
1789  // read the data the first time.
1790  if (LoadParkXML() != nullptr)
1791  LOG_DEBUG("Failed to refresh parking data.");
1792 
1793  wordexp_t wexp;
1794  FILE * fp;
1795  char pcdata[30];
1796  ParkDeviceName = getDeviceName();
1797 
1798  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
1799  {
1800  wordfree(&wexp);
1801  LOGF_INFO("WriteParkData: can not write file %s: Badly formed filename.",
1802  ParkDataFileName.c_str());
1803  return false;
1804  }
1805 
1806  if (!(fp = fopen(wexp.we_wordv[0], "w")))
1807  {
1808  wordfree(&wexp);
1809  LOGF_INFO("WriteParkData: can not write file %s: %s", ParkDataFileName.c_str(),
1810  strerror(errno));
1811  return false;
1812  }
1813 
1814  if (!ParkdataXmlRoot)
1815  ParkdataXmlRoot = addXMLEle(nullptr, "parkdata");
1816 
1817  if (!ParkdeviceXml)
1818  {
1819  ParkdeviceXml = addXMLEle(ParkdataXmlRoot, "device");
1820  addXMLAtt(ParkdeviceXml, "name", ParkDeviceName);
1821  }
1822 
1823  if (!ParkstatusXml)
1824  ParkstatusXml = addXMLEle(ParkdeviceXml, "parkstatus");
1825  if (parkDataType != PARK_NONE)
1826  {
1827  if (!ParkpositionXml)
1828  ParkpositionXml = addXMLEle(ParkdeviceXml, "parkposition");
1829  if (!ParkpositionAxis1Xml)
1830  ParkpositionAxis1Xml = addXMLEle(ParkpositionXml, "axis1position");
1831  }
1832 
1833  editXMLEle(ParkstatusXml, (IsParked ? "true" : "false"));
1834 
1835  if (parkDataType != PARK_NONE)
1836  {
1837  snprintf(pcdata, sizeof(pcdata), "%lf", Axis1ParkPosition);
1838  editXMLEle(ParkpositionAxis1Xml, pcdata);
1839  }
1840 
1841  prXMLEle(fp, ParkdataXmlRoot, 0);
1842  fclose(fp);
1843  wordfree(&wexp);
1844 
1845  return true;
1846 }
1847 
1849 {
1850  return Axis1ParkPosition;
1851 }
1852 
1854 {
1855  return Axis1DefaultParkPosition;
1856 }
1857 
1858 void Dome::SetAxis1Park(double value)
1859 {
1860  Axis1ParkPosition = value;
1861  ParkPositionN[AXIS_RA].value = value;
1862  IDSetNumber(&ParkPositionNP, nullptr);
1863 }
1864 
1865 void Dome::SetAxis1ParkDefault(double value)
1866 {
1867  Axis1DefaultParkPosition = value;
1868 }
1869 
1871 {
1872  // Check if it is already parked.
1873  if (CanPark())
1874  {
1875  if (parkDataType != PARK_NONE && isParked())
1876  {
1877  LOG_WARN( "Please unpark the dome before issuing any motion commands.");
1878  return IPS_ALERT;
1879  }
1880  }
1881 
1882  if ((DomeMotionSP.s != IPS_BUSY && (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY)) ||
1884  {
1885  LOG_WARN( "Please stop dome before issuing any further motion commands.");
1886  return IPS_ALERT;
1887  }
1888 
1889  int current_direction = IUFindOnSwitchIndex(&DomeMotionSP);
1890 
1891  // if same move requested, return
1892  if (DomeMotionSP.s == IPS_BUSY && current_direction == dir && operation == MOTION_START)
1893  return IPS_BUSY;
1894 
1895  DomeMotionSP.s = Move(dir, operation);
1896 
1897  if (DomeMotionSP.s == IPS_BUSY || DomeMotionSP.s == IPS_OK)
1898  {
1899  m_DomeState = (operation == MOTION_START) ? DOME_MOVING : DOME_IDLE;
1901  if (operation == MOTION_START)
1902  DomeMotionS[dir].s = ISS_ON;
1903  }
1904 
1905  IDSetSwitch(&DomeMotionSP, nullptr);
1906 
1907  return DomeMotionSP.s;
1908 }
1909 
1910 IPState Dome::MoveRel(double azDiff)
1911 {
1912  if (CanRelMove() == false)
1913  {
1914  LOG_ERROR( "Dome does not support relative motion.");
1915  return IPS_ALERT;
1916  }
1917 
1918  if (m_DomeState == DOME_PARKED)
1919  {
1920  LOG_ERROR( "Please unpark before issuing any motion commands.");
1922  IDSetNumber(&DomeRelPosNP, nullptr);
1923  return IPS_ALERT;
1924  }
1925 
1927  {
1928  LOG_WARN( "Please stop dome before issuing any further motion commands.");
1930  IDSetNumber(&DomeRelPosNP, nullptr);
1931  return IPS_ALERT;
1932  }
1933 
1934  IPState rc;
1935 
1936  if ((rc = MoveRel(azDiff)) == IPS_OK)
1937  {
1939  DomeRelPosNP.s = IPS_OK;
1940  DomeRelPosN[0].value = azDiff;
1941  IDSetNumber(&DomeRelPosNP, "Dome moved %.2f degrees %s.", azDiff,
1942  (azDiff > 0) ? "clockwise" : "counter clockwise");
1943  if (CanAbsMove())
1944  {
1945  DomeAbsPosNP.s = IPS_OK;
1946  IDSetNumber(&DomeAbsPosNP, nullptr);
1947  }
1948  return IPS_OK;
1949  }
1950  else if (rc == IPS_BUSY)
1951  {
1953  DomeRelPosN[0].value = azDiff;
1955  IDSetNumber(&DomeRelPosNP, "Dome is moving %.2f degrees %s...", azDiff,
1956  (azDiff > 0) ? "clockwise" : "counter clockwise");
1957  if (CanAbsMove())
1958  {
1960  IDSetNumber(&DomeAbsPosNP, nullptr);
1961  }
1962 
1965  DomeMotionS[DOME_CW].s = (azDiff > 0) ? ISS_ON : ISS_OFF;
1966  DomeMotionS[DOME_CCW].s = (azDiff < 0) ? ISS_ON : ISS_OFF;
1967  IDSetSwitch(&DomeMotionSP, nullptr);
1968  return IPS_BUSY;
1969  }
1970 
1973  LOG_WARN("Dome failed to move to new requested position.");
1974  IDSetNumber(&DomeRelPosNP, nullptr);
1975  return IPS_ALERT;
1976 }
1977 
1979 {
1980  if (CanAbsMove() == false)
1981  {
1982  LOG_ERROR("Dome does not support MoveAbs(). MoveAbs() must be implemented in the child class.");
1983  return IPS_ALERT;
1984  }
1985 
1986  if (m_DomeState == DOME_PARKED)
1987  {
1988  LOG_ERROR( "Please unpark before issuing any motion commands.");
1990  IDSetNumber(&DomeAbsPosNP, nullptr);
1991  return IPS_ALERT;
1992  }
1993 
1995  {
1996  LOG_WARN( "Please stop dome before issuing any further motion commands.");
1997  return IPS_ALERT;
1998  }
1999 
2000  IPState rc;
2001 
2002  if (az < DomeAbsPosN[0].min || az > DomeAbsPosN[0].max)
2003  {
2004  LOGF_ERROR( "Error: requested azimuth angle %.2f is out of range.", az);
2006  IDSetNumber(&DomeAbsPosNP, nullptr);
2007  return IPS_ALERT;
2008  }
2009 
2010  if ((rc = MoveAbs(az)) == IPS_OK)
2011  {
2013  DomeAbsPosNP.s = IPS_OK;
2014  DomeAbsPosN[0].value = az;
2015  LOGF_INFO("Dome moved to position %.2f degrees azimuth.", az);
2016  IDSetNumber(&DomeAbsPosNP, nullptr);
2017 
2018  return IPS_OK;
2019  }
2020  else if (rc == IPS_BUSY)
2021  {
2024  LOGF_INFO("Dome is moving to position %.2f degrees azimuth...", az);
2025  IDSetNumber(&DomeAbsPosNP, nullptr);
2026 
2029  DomeMotionS[DOME_CW].s = (az > DomeAbsPosN[0].value) ? ISS_ON : ISS_OFF;
2030  DomeMotionS[DOME_CCW].s = (az < DomeAbsPosN[0].value) ? ISS_ON : ISS_OFF;
2031  IDSetSwitch(&DomeMotionSP, nullptr);
2032 
2033  return IPS_BUSY;
2034  }
2035 
2038  IDSetNumber(&DomeAbsPosNP, "Dome failed to move to new requested position.");
2039  return IPS_ALERT;
2040 }
2041 
2042 bool Dome::Sync(double az)
2043 {
2044  INDI_UNUSED(az);
2045  LOG_WARN("Syncing is not supported.");
2046  return false;
2047 }
2048 
2050 {
2051  if (CanAbort() == false)
2052  {
2053  LOG_ERROR( "Dome does not support abort.");
2054  return false;
2055  }
2056 
2058 
2059  if (Abort())
2060  {
2061  AbortSP.s = IPS_OK;
2062 
2064  {
2066  if (m_DomeState == DOME_PARKING)
2067  {
2068  DEBUG(Logger::DBG_SESSION, "Parking aborted.");
2069  // If parking was aborted then it was UNPARKED before
2070  ParkS[1].s = ISS_ON;
2071  }
2072  else
2073  {
2074  DEBUG(Logger::DBG_SESSION, "UnParking aborted.");
2075  // If unparking aborted then it was PARKED before
2076  ParkS[0].s = ISS_ON;
2077  }
2078 
2079  ParkSP.s = IPS_ALERT;
2080  IDSetSwitch(&ParkSP, nullptr);
2081  }
2082 
2084  }
2085  else
2086  {
2087  AbortSP.s = IPS_ALERT;
2088 
2089  // If alert was aborted during parking or unparking, the parking state is unknown
2091  {
2093  ParkSP.s = IPS_IDLE;
2094  IDSetSwitch(&ParkSP, nullptr);
2095  }
2096  }
2097 
2098  IDSetSwitch(&AbortSP, nullptr);
2099 
2100  return (AbortSP.s == IPS_OK);
2101 }
2102 
2103 bool Dome::SetSpeed(double speed)
2104 {
2105  if (HasVariableSpeed() == false)
2106  {
2107  LOG_ERROR( "Dome does not support variable speed.");
2108  return false;
2109  }
2110 
2111  if (SetSpeed(speed))
2112  {
2113  DomeSpeedNP.s = IPS_OK;
2114  DomeSpeedN[0].value = speed;
2115  }
2116  else
2118 
2119  IDSetNumber(&DomeSpeedNP, nullptr);
2120 
2121  return (DomeSpeedNP.s == IPS_OK);
2122 }
2123 
2125 {
2126  if (HasShutter() == false)
2127  {
2128  LOG_ERROR( "Dome does not have shutter control.");
2129  return IPS_ALERT;
2130  }
2131 
2132  // if (weatherState == IPS_ALERT && operation == SHUTTER_OPEN)
2133  // {
2134  // LOG_WARN( "Weather is in the danger zone! Cannot open shutter.");
2135  // return IPS_ALERT;
2136  // }
2137 
2138  int currentStatus = IUFindOnSwitchIndex(&DomeShutterSP);
2139 
2140  // No change of status, let's return
2141  if (DomeShutterSP.s == IPS_BUSY && currentStatus == operation)
2142  {
2143  IDSetSwitch(&DomeShutterSP, nullptr);
2144  return DomeShutterSP.s;
2145  }
2146 
2147  DomeShutterSP.s = ControlShutter(operation);
2148 
2149  if (DomeShutterSP.s == IPS_OK)
2150  {
2151  IDSetSwitch(&DomeShutterSP, "Shutter is %s.", (operation == SHUTTER_OPEN ? "open" : "closed"));
2153  return DomeShutterSP.s;
2154  }
2155  else if (DomeShutterSP.s == IPS_BUSY)
2156  {
2158  DomeShutterS[operation].s = ISS_ON;
2159  IDSetSwitch(&DomeShutterSP, "Shutter is %s...", (operation == 0 ? "opening" : "closing"));
2161  return DomeShutterSP.s;
2162  }
2163 
2164  IDSetSwitch(&DomeShutterSP, "Shutter failed to %s.", (operation == 0 ? "open" : "close"));
2165  return IPS_ALERT;
2166 }
2167 
2169 {
2170  // Not really supposed to get this at all, but just in case.
2171  if (CanPark() == false)
2172  {
2173  LOG_ERROR( "Dome does not support parking.");
2174  return IPS_ALERT;
2175  }
2176 
2177  // No need to park if parked already.
2178  if (m_DomeState == DOME_PARKED)
2179  {
2181  ParkS[0].s = ISS_ON;
2182  LOG_INFO("Dome already parked.");
2183  IDSetSwitch(&ParkSP, nullptr);
2184  return IPS_OK;
2185  }
2186 
2187  // Check if dome is locked due to Mount Policy
2188  if (isLocked())
2189  {
2191  ParkS[1].s = ISS_ON;
2192  ParkSP.s = IPS_ALERT;
2193  IDSetSwitch(&ParkSP, nullptr);
2194  LOG_INFO("Cannot Park Dome when mount is locking. See: Mount Policy in options tab.");
2195  return IPS_ALERT;
2196  }
2197 
2198  // Now ask child driver to start the actual parking process.
2199  ParkSP.s = Park();
2200 
2201  // IPS_OK is when it is immediately parked so realisticly this does not happen
2202  // unless dome is physically parked but just needed a state change.
2203  if (ParkSP.s == IPS_OK)
2204  SetParked(true);
2205  // Dome is moving to parking position
2206  else if (ParkSP.s == IPS_BUSY)
2207  {
2209 
2210  if (CanAbsMove())
2212 
2214  ParkS[0].s = ISS_ON;
2215  }
2216  else
2217  IDSetSwitch(&ParkSP, nullptr);
2218 
2219  return ParkSP.s;
2220 }
2221 
2223 {
2224  if (CanPark() == false)
2225  {
2226  LOG_ERROR( "Dome does not support parking.");
2227  return IPS_ALERT;
2228  }
2229 
2230  if (m_DomeState != DOME_PARKED)
2231  {
2233  ParkS[1].s = ISS_ON;
2234  DEBUG(Logger::DBG_SESSION, "Dome already unparked.");
2235  IDSetSwitch(&ParkSP, nullptr);
2236  return IPS_OK;
2237  }
2238 
2239  // if (weatherState == IPS_ALERT)
2240  // {
2241  // LOG_WARN( "Weather is in the danger zone! Cannot unpark dome.");
2242  // ParkSP.s = IPS_OK;
2243  // IDSetSwitch(&ParkSP, nullptr);
2244  // return IPS_ALERT;
2245  // }
2246 
2247  ParkSP.s = UnPark();
2248 
2249  if (ParkSP.s == IPS_OK)
2250  SetParked(false);
2251  else if (ParkSP.s == IPS_BUSY)
2253  else
2254  IDSetSwitch(&ParkSP, nullptr);
2255 
2256  return ParkSP.s;
2257 }
2258 
2260 {
2261  LOG_WARN( "Parking is not supported.");
2262  return false;
2263 }
2264 
2266 {
2267  LOG_WARN( "Parking is not supported.");
2268  return false;
2269 }
2270 
2272 {
2273  return false;
2274 }
2275 
2276 bool Dome::callHandshake()
2277 {
2278  if (domeConnection > 0)
2279  {
2282  else if (getActiveConnection() == tcpConnection)
2284  }
2285 
2286  return Handshake();
2287 }
2288 
2290 {
2291  return domeConnection;
2292 }
2293 
2294 void Dome::setDomeConnection(const uint8_t &value)
2295 {
2297 
2298  if (value == 0 || (mask & value) == 0)
2299  {
2300  LOGF_ERROR( "Invalid connection mode %d", value);
2301  return;
2302  }
2303 
2304  domeConnection = value;
2305 }
2306 
2307 }
INDI::Dome::ActiveDeviceTP
ITextVectorProperty ActiveDeviceTP
Definition: indidome.h:566
crackIPState
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indicom.c:1211
INDI::Dome::Dome
Dome()
Definition: indidome.cpp:50
INDI::Dome::SetAxis1Park
void SetAxis1Park(double value)
SetRAPark Set current AZ parking position. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1858
INDI::Dome::Park
virtual IPState Park()
Goto Park Position. The park position is an absolute azimuth value.
Definition: indidome.cpp:2168
INDI::Dome::DOME_PARKED
@ DOME_PARKED
Definition: indidome.h:136
INDI::Dome::DM_OTA_SIDE_HA
@ DM_OTA_SIDE_HA
Definition: indidome.h:598
INDI::Dome::PresetGotoS
ISwitch PresetGotoS[3]
Definition: indidome.h:584
newLilXML
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.c:148
IUGetConfigSwitch
int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
IUGetConfigSwitch Opens configuration file and reads single switch property.
Definition: indidriver.c:1212
Connection::TCP::getPortFD
int getPortFD() const
Definition: connectiontcp.h:105
INDI::Dome::MOUNT_IGNORED
@ MOUNT_IGNORED
Definition: indidome.h:122
INDI::Dome::DomeRelPosN
INumber DomeRelPosN[1]
Definition: indidome.h:537
INDI::Dome::DomeSpeedN
INumber DomeSpeedN[1]
Definition: indidome.h:528
INDI::Dome::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indidome.cpp:93
rangeHA
double rangeHA(double r)
rangeHA Limits the hour angle value to be between -12 —> 12
Definition: indicom.c:1454
DOME_COORD_THRESHOLD
#define DOME_COORD_THRESHOLD
Definition: indidome.cpp:44
INDI::Dome::SetBacklash
virtual bool SetBacklash(int32_t steps)
SetBacklash Set the dome backlash compensation value.
Definition: indidome.cpp:1025
IPState
IPState
Property state.
Definition: indiapi.h:158
INDI::Dome
Class to provide general functionality of a Dome device.
Definition: indidome.h:74
INDI::IHorizontalCoordinates::azimuth
double azimuth
Definition: libastro.h:58
INDI::Dome::UnPark
virtual IPState UnPark()
UnPark dome. The action of the Unpark command is dome specific, but it may include opening the shutte...
Definition: indidome.cpp:2222
INDI::Dome::DOME_UNKNOWN
@ DOME_UNKNOWN
Definition: indidome.h:138
INDI::Dome::prev_alt
double prev_alt
Definition: indidome.h:614
INDI::IEquatorialCoordinates::declination
double declination
Definition: libastro.h:51
INDI::Dome::SetParkDataType
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:1584
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
INDI::Dome::SHUTTER_UNKNOWN
@ SHUTTER_UNKNOWN
Definition: indidome.h:150
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
INDI::Dome::MoveAbs
virtual IPState MoveAbs(double az)
Move the Dome to an absolute azimuth.
Definition: indidome.cpp:1978
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
INDI::Dome::ActiveDeviceT
IText ActiveDeviceT[1]
Definition: indidome.h:567
min
double min(void)
INDI::Dome::DomeSpeedNP
INumberVectorProperty DomeSpeedNP
Definition: indidome.h:527
INDI::Dome::DomeShutterS
ISwitch DomeShutterS[2]
Definition: indidome.h:549
INDI::Dome::tcpConnection
Connection::TCP * tcpConnection
Definition: indidome.h:620
ISwitch
One switch descriptor.
INDI::Dome::Move
virtual IPState Move(DomeDirection dir, DomeMotionCommand operation)
Move the Dome in a particular direction.
Definition: indidome.cpp:1870
INDI::Controller::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
Definition: indicontroller.cpp:302
INDI::Dome::DM_OTA_SIDE_EAST
@ DM_OTA_SIDE_EAST
Definition: indidome.h:595
INDI::Dome::AbortS
ISwitch AbortS[1]
Definition: indidome.h:540
INDI::Dome::OpticalCenter
bool OpticalCenter(point3D MountCenter, double dOpticalAxis, double Lat, double Ah, point3D &OP)
OpticalCenter This function calculates the distance from the optical axis to the Dome center.
Definition: indidome.cpp:1429
INDI::Controller
The Controller class provides functionality to access a controller (e.g. joystick) input and send it ...
Definition: indicontroller.h:81
INDI::Dome::buttonHelper
static void buttonHelper(const char *button_n, ISState state, void *context)
Definition: indidome.cpp:1080
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
INDI::Dome::SetSpeed
virtual bool SetSpeed(double rpm)
SetSpeed Set Dome speed. This does not initiate motion, it sets the speed for the next motion command...
Definition: indidome.cpp:2103
pcdataXMLEle
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:575
indicom.h
Implementations for common driver routines.
connectiontcp.h
point3D::y
double y
Definition: indidome.h:54
INDI::Dome::ISNewSwitch
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
INDI::Dome::parkDataType
DomeParkData parkDataType
Definition: indidome.h:564
INDI::Logger::DBG_WARNING
@ DBG_WARNING
Definition: indilogger.h:193
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
INDI::Dome::SHUTTER_ERROR
@ SHUTTER_ERROR
Definition: indidome.h:151
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
INDI::Dome::mountEquatorialCoords
INDI::IEquatorialCoordinates mountEquatorialCoords
Definition: indidome.h:634
nextXMLEle
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:524
IDSnoopDevice
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:137
f_scansexa
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:195
INDI::Dome::OpticalVector
bool OpticalVector(double Az, double Alt, point3D &OV)
OpticalVector This function calculates a second point for determining the optical axis.
Definition: indidome.cpp:1450
inditimer.h
Connection::Serial
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
Definition: connectionserial.h:56
INDI::Dome::MOTION_START
@ MOTION_START
Definition: indidome.h:98
Connection::TCP
The TCP class manages connection with devices over the network via TCP/IP. Upon successfull connectio...
Definition: connectiontcp.h:55
IUFillNumber
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: indidriver.c:348
INDI::Dome::DomeParkData
DomeParkData
Definition: indidome.h:103
ISR_NOFMANY
@ ISR_NOFMANY
Definition: indiapi.h:174
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
INDI::Dome::MOUNT_LOCKS
@ MOUNT_LOCKS
Definition: indidome.h:123
OPTIONS_TAB
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Definition: defaultdevice.cpp:39
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
INDI::Controller::setButtonCallback
void setButtonCallback(buttonFunc buttonCallback)
setButtonCallback Sets the callback function when a new button input is detected.
Definition: indicontroller.cpp:340
INDI::Dome::DOME_SYNCED
@ DOME_SYNCED
Definition: indidome.h:133
INDI::Dome::DM_NORTH_DISPLACEMENT
@ DM_NORTH_DISPLACEMENT
Definition: indidome.h:85
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
INDI::Dome::Csc
double Csc(double x)
Definition: indidome.cpp:1463
IUFillTextVector
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: indidriver.c:477
INDI::Dome::DOME_UNPARKED
@ DOME_UNPARKED
Definition: indidome.h:137
INDI::Dome::SetDefaultPark
virtual bool SetDefaultPark()
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: indidome.cpp:2265
INDI::Dome::DomeBacklashNP
INumberVectorProperty DomeBacklashNP
Definition: indidome.h:611
INDI::Dome::ParkOptionSP
ISwitchVectorProperty ParkOptionSP
Definition: indidome.h:558
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::Dome::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Dome Presets in the configuration file
Definition: indidome.cpp:1041
INDI::Dome::isLocked
bool isLocked()
isLocked, is the dome currently locked?
Definition: indidome.cpp:1075
INDI::Dome::MoveRel
virtual IPState MoveRel(double azDiff)
Move the Dome to an relative position.
Definition: indidome.cpp:1910
INDI::Dome::DomeDirection
DomeDirection
Definition: indidome.h:91
INDI::Dome::CONNECTION_SERIAL
@ CONNECTION_SERIAL
Definition: indidome.h:172
INDI::Dome::DOME_ERROR
@ DOME_ERROR
Definition: indidome.h:139
SITE_TAB
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
Definition: defaultdevice.cpp:38
INDI::Dome::Abort
virtual bool Abort()
Abort all dome motion.
Definition: indidome.cpp:2049
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::Dome::ParkSP
ISwitchVectorProperty ParkSP
Definition: indidome.h:551
INDI::Dome::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: indidome.cpp:795
INDI::Dome::CanRelMove
bool CanRelMove()
Definition: indidome.h:234
INDI::Dome::CanAbsMove
bool CanAbsMove()
Definition: indidome.h:226
INDI::Dome::SHUTTER_OPENED
@ SHUTTER_OPENED
Definition: indidome.h:147
INDI::Logger::DBG_SESSION
@ DBG_SESSION
Definition: indilogger.h:194
INDI::Dome::ShutterParkPolicyS
ISwitch ShutterParkPolicyS[2]
Definition: indidome.h:575
INDI::Dome::SHUTTER_CLOSED
@ SHUTTER_CLOSED
Definition: indidome.h:148
INDI::Dome::DomeAutoSyncSP
ISwitchVectorProperty DomeAutoSyncSP
Definition: indidome.h:603
INDI::Dome::DomeParamNP
INumberVectorProperty DomeParamNP
Definition: indidome.h:542
INDI::Dome::UpdateMountCoords
void UpdateMountCoords()
updateCoords updates the horizontal coordinates (Az & Alt) of the mount from the snooped RA,...
Definition: indidome.cpp:1485
INDI::Dome::setDomeState
void setDomeState(const DomeState &value)
Definition: indidome.cpp:1154
INDI::Dome::GetTargetAz
bool GetTargetAz(double &Az, double &Alt, double &minAz, double &maxAz)
GetTargetAz.
Definition: indidome.cpp:1271
INDI::Dome::DM_OTA_OFFSET
@ DM_OTA_OFFSET
Definition: indidome.h:88
addXMLAtt
XMLAtt * addXMLAtt(XMLEle *ep, const char *name, const char *valu)
Add an XML attribute to an existing XML element.
Definition: lilxml.c:664
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1434
IUFillText
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: indidriver.c:369
IUUpdateText
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:259
point3D::x
double x
Definition: indidome.h:54
DEBUGDEVICE
#define DEBUGDEVICE(device, priority, msg)
Definition: indilogger.h:60
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
INDI::Controller::mapController
void mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue)
mapController adds a new property to the joystick's settings.
Definition: indicontroller.cpp:61
INDI::Dome::serialConnection
Connection::Serial * serialConnection
Definition: indidome.h:619
INDI::Dome::DomeRelPosNP
INumberVectorProperty DomeRelPosNP
Definition: indidome.h:536
INDI::Dome::observer
IGeographicCoordinates observer
Definition: indidome.h:628
DEBUG
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
INDI::DefaultDevice::initProperties
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
Definition: defaultdevice.cpp:917
max
double max(void)
INDI::Dome::mountOTASide
int mountOTASide
Definition: indidome.h:602
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1421
INDI::Dome::CONNECTION_NONE
@ CONNECTION_NONE
Definition: indidome.h:171
INDI::Dome::DM_SHUTTER_WIDTH
@ DM_SHUTTER_WIDTH
Definition: indidome.h:84
IUFindOnSwitch
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *sp)
Returns the first ON switch it finds in the vector switch property.
Definition: indicom.c:1393
INDI::Dome::GetAxis1Park
double GetAxis1Park()
Definition: indidome.cpp:1848
INDI::Dome::DomeBacklashSP
ISwitchVectorProperty DomeBacklashSP
Definition: indidome.h:607
INDI::Dome::SHUTTER_CLOSE_ON_PARK
@ SHUTTER_CLOSE_ON_PARK
Definition: indidome.h:578
INDI::Dome::HaveLatLong
bool HaveLatLong
Definition: indidome.h:630
INDI::Timer::start
void start()
Starts or restarts the timer with the timeout specified in interval.
Definition: inditimer.cpp:78
INDI::Dome::HasVariableSpeed
bool HasVariableSpeed()
Definition: indidome.h:266
INDI::Dome::DOME_MOVING
@ DOME_MOVING
Definition: indidome.h:132
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
INDI::DefaultDevice::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: defaultdevice.cpp:633
type
__le16 type
Definition: pwc-ioctl.h:2
INDI::Dome::mountHoriztonalCoords
INDI::IHorizontalCoordinates mountHoriztonalCoords
Definition: indidome.h:633
INDI::IEquatorialCoordinates::rightascension
double rightascension
Definition: libastro.h:50
INDI::Dome::DM_OTA_SIDE_WEST
@ DM_OTA_SIDE_WEST
Definition: indidome.h:596
INDI::Dome::DM_EAST_DISPLACEMENT
@ DM_EAST_DISPLACEMENT
Definition: indidome.h:86
INDI::Dome::PresetN
INumber PresetN[3]
Definition: indidome.h:582
delLilXML
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.c:157
INDI::IGeographicCoordinates::longitude
double longitude
Definition: libastro.h:66
INDI::Dome::getDomeConnection
uint8_t getDomeConnection() const
Definition: indidome.cpp:2289
INDI::Dome::DomeMeasurementsN
INumber DomeMeasurementsN[6]
Definition: indidome.h:586
indidome.h
INDI::Dome::m_DomeState
DomeState m_DomeState
Definition: indidome.h:623
IUSaveConfigText
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indicom.c:1439
ra
double ra
Definition: ieqprolegacydriver.cpp:43
INDI::Dome::HasShutter
bool HasShutter()
Definition: indidome.h:258
INDI::Controller::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Definition: indicontroller.cpp:158
INDI::Dome::ControlShutter
virtual IPState ControlShutter(ShutterOperation operation)
Open or Close shutter.
Definition: indidome.cpp:2124
INDI::IGeographicCoordinates::latitude
double latitude
Definition: libastro.h:67
INDI::Dome::GetShutterStatusString
const char * GetShutterStatusString(ShutterState status)
getShutterStatusString
Definition: indidome.cpp:1566
INDI::Dome::DM_OTA_SIDE_IGNORE
@ DM_OTA_SIDE_IGNORE
Definition: indidome.h:599
INDI::Dome::LoadParkData
const char * LoadParkData()
Definition: indidome.cpp:1755
INDI::Dome::SetBacklashEnabled
virtual bool SetBacklashEnabled(bool enabled)
SetBacklashEnabled Enables or disables the dome backlash compensation.
Definition: indidome.cpp:1032
INDI::Controller::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root)
Definition: indicontroller.cpp:239
INDI::Controller::ISGetProperties
virtual void ISGetProperties(const char *dev)
Definition: indicontroller.cpp:123
INDI::Dome::ISNewNumber
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
INDI::Dome::ParkPositionNP
INumberVectorProperty ParkPositionNP
Definition: indidome.h:555
INDI::DefaultDevice::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
Definition: defaultdevice.cpp:593
xml_att_
Definition: lilxml.c:120
IUFillSwitchVector
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: indidriver.c:412
INDI::Dome::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: indidome.cpp:822
INDI::BaseDevice::DOME_INTERFACE
@ DOME_INTERFACE
Definition: basedevice.h:77
INDI::EquatorialToHorizontal
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
Definition: libastro.cpp:140
IUFillNumberVector
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: indidriver.c:455
editXMLEle
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
Definition: lilxml.c:656
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
connectionserial.h
INDI::Dome::PresetGotoSP
ISwitchVectorProperty PresetGotoSP
Definition: indidome.h:585
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::Dome::DomeAutoSyncS
ISwitch DomeAutoSyncS[2]
Definition: indidome.h:604
INDI::Dome::AbortSP
ISwitchVectorProperty AbortSP
Definition: indidome.h:539
INDI::Dome::m_MountState
IPState m_MountState
Definition: indidome.h:625
INDI::IHorizontalCoordinates::altitude
double altitude
Definition: libastro.h:59
INDI::Dome::~Dome
virtual ~Dome()
Definition: indidome.cpp:71
INDI::Dome::MOTION_STOP
@ MOTION_STOP
Definition: indidome.h:99
INDI::Dome::SHUTTER_OPEN
@ SHUTTER_OPEN
Definition: indidome.h:115
INDI::DefaultDevice::registerConnection
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
Definition: defaultdevice.cpp:1107
dec
double dec
Definition: ieqprolegacydriver.cpp:44
readXMLFile
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.c:622
INDI::Dome::DomeSyncN
INumber DomeSyncN[1]
Definition: indidome.h:546
tagXMLEle
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:569
xml_ele_
Definition: lilxml.c:105
INDI::Dome::SetAxis1ParkDefault
void SetAxis1ParkDefault(double steps)
SetAxis1Park Set default AZ parking position.
Definition: indidome.cpp:1865
INDI::Dome::DomeState
DomeState
Dome status.
Definition: indidome.h:129
point3D
Definition: indidome.h:32
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
point3D::z
double z
Definition: indidome.h:54
INDI::Dome::OTASideS
ISwitch OTASideS[5]
Definition: indidome.h:590
INDI::Timer::callOnTimeout
void callOnTimeout(const std::function< void()> &callback)
Definition: inditimer.cpp:72
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::Dome::getMountState
IPState getMountState() const
Definition: indidome.cpp:1112
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
INDI::Dome::DomeSyncNP
INumberVectorProperty DomeSyncNP
Definition: indidome.h:545
INDI::Dome::ShutterOperation
ShutterOperation
Shutter operation command.
Definition: indidome.h:113
INDI::Dome::DM_DOME_RADIUS
@ DM_DOME_RADIUS
Definition: indidome.h:83
INDI::Dome::DM_UP_DISPLACEMENT
@ DM_UP_DISPLACEMENT
Definition: indidome.h:87
LOG_DEBUG
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
INDI::Dome::HaveRaDec
bool HaveRaDec
Definition: indidome.h:636
INDI::Dome::OTASideSP
ISwitchVectorProperty OTASideSP
Definition: indidome.h:589
INDI::Dome::SHUTTER_MOVING
@ SHUTTER_MOVING
Definition: indidome.h:149
INDI::Dome::DomeMotionCommand
DomeMotionCommand
Definition: indidome.h:96
INDI::Dome::DomeBacklashN
INumber DomeBacklashN[1]
Definition: indidome.h:612
INDI::Dome::GetAxis1ParkDefault
double GetAxis1ParkDefault()
Definition: indidome.cpp:1853
INDI::Dome::CanSync
bool CanSync()
Definition: indidome.h:250
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
indicontroller.h
INDI::Dome::DomeShutterSP
ISwitchVectorProperty DomeShutterSP
Definition: indidome.h:548
INDI::Dome::isParked
bool isParked()
isParked is dome currently parked?
Definition: indidome.cpp:1636
INDI::Dome::WriteParkData
bool WriteParkData()
Definition: indidome.cpp:1786
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
INDI::Dome::setShutterState
void setShutterState(const ShutterState &value)
Definition: indidome.cpp:1117
INDI::Dome::DOME_UNPARKING
@ DOME_UNPARKING
Definition: indidome.h:135
INDI::Dome::HasBacklash
bool HasBacklash()
Definition: indidome.h:274
INDI::Controller::CONTROLLER_BUTTON
@ CONTROLLER_BUTTON
Definition: indicontroller.h:84
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
INDI::Dome::CheckHorizon
bool CheckHorizon(double HA, double dec, double lat)
CheckHorizon Returns true if telescope points above horizon.
Definition: indidome.cpp:1473
INDI::DefaultDevice::ISGetProperties
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: defaultdevice.cpp:750
INDI::Dome::SetParked
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1630
INDI::Dome::Intersection
bool Intersection(point3D p1, point3D p2, double r, double &mu1, double &mu2)
Intersection Calculate the intersection of a ray and a sphere. The line segment is defined from p1 to...
Definition: indidome.cpp:1405
DOME_SLAVING_TAB
#define DOME_SLAVING_TAB
Definition: indidome.cpp:43
INDI::Dome::DomeMeasurementsNP
INumberVectorProperty DomeMeasurementsNP
Definition: indidome.h:587
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::Dome::prev_az
double prev_az
Definition: indidome.h:614
valuXMLAtt
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:593
findXMLEle
XMLEle * findXMLEle(XMLEle *ep, const char *tag)
Find an XML element within an XML element.
Definition: lilxml.c:506
INDI::Timer::stop
void stop()
Stops the timer.
Definition: inditimer.cpp:93
AXIS_AZ
@ AXIS_AZ
Definition: indibasetypes.h:39
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
INDI::Dome::ISGetProperties
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indidome.cpp:259
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
AXIS_RA
@ AXIS_RA
Definition: indibasetypes.h:33
Connection::Interface::registerHandshake
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
Definition: connectioninterface.cpp:108
INDI::Dome::ShutterParkPolicySP
ISwitchVectorProperty ShutterParkPolicySP
Definition: indidome.h:574
INDI::Dome::CONNECTION_TCP
@ CONNECTION_TCP
Definition: indidome.h:173
INDI::Dome::DomeParamN
INumber DomeParamN[1]
Definition: indidome.h:543
INDI::Dome::Sync
virtual bool Sync(double az)
Sync sets the dome current azimuth as the supplied azimuth position.
Definition: indidome.cpp:2042
INDI::Dome::CanPark
bool CanPark()
Definition: indidome.h:242
prXMLEle
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.c:699
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
INDI::Dome::prev_dec
double prev_dec
Definition: indidome.h:614
INDI::Dome::DM_OTA_SIDE_MOUNT
@ DM_OTA_SIDE_MOUNT
Definition: indidome.h:597
INDI::Dome::ParkS
ISwitch ParkS[2]
Definition: indidome.h:552
INDI::Dome::m_ShutterState
ShutterState m_ShutterState
Definition: indidome.h:624
INDI::Dome::DOME_CCW
@ DOME_CCW
Definition: indidome.h:94
fs_sexa
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string.
Definition: indicom.c:131
INDI::DefaultDevice::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: defaultdevice.cpp:175
INDI::Dome::DomeAbsPosNP
INumberVectorProperty DomeAbsPosNP
Definition: indidome.h:533
findXMLAttValu
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:613
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
MAXINDILABEL
#define MAXINDILABEL
Definition: indiapi.h:191
INDI::Dome::Sec
double Sec(double x)
Definition: indidome.cpp:1468
INDI::Dome::MountPolicySP
ISwitchVectorProperty MountPolicySP
Definition: indidome.h:570
INDI::Dome::PresetNP
INumberVectorProperty PresetNP
Definition: indidome.h:583
INDI::Dome::InitPark
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Definition: indidome.cpp:1641
LilXML_
Definition: lilxml.c:91
INDI::Dome::setDomeConnection
void setDomeConnection(const uint8_t &value)
setDomeConnection Set Dome connection mode. Child class should call this in the constructor before Do...
Definition: indidome.cpp:2294
INDI::Dome::DOME_CW
@ DOME_CW
Definition: indidome.h:93
INDI::Dome::SetDomeCapability
void SetDomeCapability(uint32_t cap)
SetDomeCapability set the dome capabilities. All capabilities must be initialized.
Definition: indidome.cpp:1558
INDI::Controller::initProperties
virtual bool initProperties()
Definition: indicontroller.cpp:109
INDI::BaseDevice::INDI_DISABLED
@ INDI_DISABLED
Definition: basedevice.h:65
INDI::Dome::PARK_AZ_ENCODER
@ PARK_AZ_ENCODER
Definition: indidome.h:107
INDI::Dome::DomeBacklashS
ISwitch DomeBacklashS[2]
Definition: indidome.h:608
INDI::Dome::CanAbort
bool CanAbort()
Definition: indidome.h:218
ISState
ISState
Switch state.
Definition: indiapi.h:148
INDI::Dome::DomeMotionSP
ISwitchVectorProperty DomeMotionSP
Definition: indidome.h:530
Connection::Serial::getPortFD
int getPortFD() const
Definition: connectionserial.h:136
INDI::Dome::DomeMotionS
ISwitch DomeMotionS[2]
Definition: indidome.h:531
INDI::Dome::PARK_AZ
@ PARK_AZ
Definition: indidome.h:106
INDI::DefaultDevice::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
Definition: defaultdevice.cpp:409
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1403
INDI::Dome::DOME_PARKING
@ DOME_PARKING
Definition: indidome.h:134
INDI::Dome::prev_ra
double prev_ra
Definition: indidome.h:614
INDI::Dome::SHUTTER_CLOSE
@ SHUTTER_CLOSE
Definition: indidome.h:116
INDI::DefaultDevice::addDebugControl
void addDebugControl()
Add Debug control to the driver.
Definition: defaultdevice.cpp:639
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1444
INDI::Dome::ParkOptionS
ISwitch ParkOptionS[3]
Definition: indidome.h:557
INDI::Dome::ParkPositionN
INumber ParkPositionN[1]
Definition: indidome.h:554
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
addXMLEle
XMLEle * addXMLEle(XMLEle *parent, const char *tag)
add an element with the given tag to the given element. parent can be NULL to make a new root.
Definition: lilxml.c:639
delXMLEle
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.c:165
INDI::DefaultDevice::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
Definition: defaultdevice.cpp:614
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
INDI::Dome::capability
uint32_t capability
Definition: indidome.h:563
INDI::Dome::DOME_IDLE
@ DOME_IDLE
Definition: indidome.h:131
INDI::Dome::SetCurrentPark
virtual bool SetCurrentPark()
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: indidome.cpp:2259
errno
int errno
INDI::Dome::SHUTTER_OPEN_ON_UNPARK
@ SHUTTER_OPEN_ON_UNPARK
Definition: indidome.h:579
INDI::Controller::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Definition: indicontroller.cpp:183
INDI::Dome::MountPolicyS
ISwitch MountPolicyS[2]
Definition: indidome.h:571
INDI::DefaultDevice::setDriverInterface
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
Definition: defaultdevice.cpp:902
INDI::Dome::DomeAbsPosN
INumber DomeAbsPosN[1]
Definition: indidome.h:534
IUFillSwitch
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: indidriver.c:320
INDI::Controller::updateProperties
virtual bool updateProperties()
Definition: indicontroller.cpp:138
findXMLAtt
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:493
INDI::Dome::ShutterState
ShutterState
Definition: indidome.h:145
INDI::Dome::Handshake
virtual bool Handshake()
perform handshake with device to check communication
Definition: indidome.cpp:2271
INDI::Dome::PortFD
int PortFD
Definition: indidome.h:617
INDI::DefaultDevice::getActiveConnection
Connection::Interface * getActiveConnection()
Definition: defaultdevice.cpp:1245
INDI::Dome::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indidome.cpp:279
INDI::Dome::PARK_NONE
@ PARK_NONE
Definition: indidome.h:105
INDI::Dome::UpdateAutoSync
virtual void UpdateAutoSync()
UpdateAutoSync This function calculates the target dome azimuth from the mount's target coordinates g...
Definition: indidome.cpp:1513
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151