Instrument Neutral Distributed Interface INDI  1.9.5
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",
858  UseHourAngle = true;
860  UseHourAngle = false;
861  }
862  }
863 
864  return true;
865  }
866  // Check EOD
867  if (!strcmp("EQUATORIAL_EOD_COORD", propName))
868  {
869  int rc_ra = -1, rc_de = -1;
870  double ra = 0, de = 0;
871 
872  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
873  {
874  const char * elemName = findXMLAttValu(ep, "name");
875 
876  if (!strcmp(elemName, "RA"))
877  rc_ra = f_scansexa(pcdataXMLEle(ep), &ra);
878  else if (!strcmp(elemName, "DEC"))
879  rc_de = f_scansexa(pcdataXMLEle(ep), &de);
880  }
881 
882  if (rc_ra == 0 && rc_de == 0)
883  {
884  // Do not spam log
885  if (std::fabs(mountEquatorialCoords.rightascension - ra) > 0.01
886  || std::fabs(mountEquatorialCoords.declination - de) > 0.01)
887  {
888  char RAStr[64] = {0}, DEStr[64] = {0};
889  fs_sexa(RAStr, ra, 2, 3600);
890  fs_sexa(DEStr, de, 2, 3600);
891 
892  LOGF_DEBUG("Snooped RA %s DEC %s", RAStr, DEStr);
893  }
894 
897  }
898 
900  crackIPState(findXMLAttValu(root, "state"), &m_MountState);
901 
902  // If the diff > 0.1 then the mount is in motion, so let's wait until it settles before moving the doom
905  {
908  //LOGF_DEBUG("Snooped RA: %g - DEC: %g", mountEquatorialCoords.rightascension, mountEquatorialCoords.declination);
909  // a mount still initializing will emit 0 and 0 on the first go
910  // we dont want to process 0/0
912  HaveRaDec = true;
913  }
914  // else mount stable, i.e. tracking, so let's update mount coords and check if we need to move
915  else if (m_MountState == IPS_OK || m_MountState == IPS_IDLE)
917 
918  return true;
919  }
920 
921  // Check Geographic coords
922  if (!strcmp("GEOGRAPHIC_COORD", propName))
923  {
924  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
925  {
926  const char * elemName = findXMLAttValu(ep, "name");
927  if (!strcmp(elemName, "LONG"))
928  {
929  double indiLong;
930  f_scansexa(pcdataXMLEle(ep), &indiLong);
931  if (indiLong > 180)
932  indiLong -= 360;
933  observer.longitude = indiLong;
934  HaveLatLong = true;
935  }
936  else if (!strcmp(elemName, "LAT"))
938  }
939 
940  LOGF_DEBUG("Snooped LONG: %g - LAT: %g", observer.longitude, observer.latitude);
941 
943 
944  return true;
945  }
946 
947  // Check Telescope Park status
948  if (!strcmp("TELESCOPE_PARK", propName))
949  {
950  if (!strcmp(findXMLAttValu(root, "state"), "Ok"))
951  {
952  bool prevState = IsLocked;
953  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
954  {
955  const char * elemName = findXMLAttValu(ep, "name");
956 
957  if ((!strcmp(elemName, "PARK") && !strcmp(pcdataXMLEle(ep), "On")))
958  IsMountParked = true;
959  else if ((!strcmp(elemName, "UNPARK") && !strcmp(pcdataXMLEle(ep), "On")))
960  IsMountParked = false;
961 
962  if (IsLocked && !strcmp(elemName, "PARK") && !strcmp(pcdataXMLEle(ep), "On"))
963  IsLocked = false;
964  else if (!IsLocked && !strcmp(elemName, "UNPARK") && !strcmp(pcdataXMLEle(ep), "On"))
965  IsLocked = true;
966  }
967  if (prevState != IsLocked && MountPolicyS[1].s == ISS_ON)
968  LOGF_INFO("Telescope status changed. Lock is set to: %s",
969  IsLocked ? "locked" : "unlocked");
970  }
971  return true;
972  }
973 
974  // Weather Status
975  // JM 2020-07-16: Weather handling moved to Watchdog driver
976 #if 0
977  if (!strcmp("WEATHER_STATUS", propName))
978  {
979  weatherState = IPS_ALERT;
980  crackIPState(findXMLAttValu(root, "state"), &weatherState);
981 
982  if (weatherState == IPS_ALERT)
983  {
984  if (CanPark())
985  {
986  if (!isParked())
987  {
988  if (AutoParkS[0].s == ISS_ON)
989  {
990  LOG_WARN("Weather conditions in the danger zone! Parking dome...");
991  Dome::Park();
992  }
993  else
994  {
995  LOG_WARN("Weather conditions in the danger zone! AutoPark is disabled. Please park the dome!");
996  }
997  }
998  }
999  else
1000  LOG_WARN("Weather conditions in the danger zone! Close the dome immediately!");
1001 
1002  return true;
1003  }
1004  }
1005 #endif
1006  if (!strcmp("TELESCOPE_PIER_SIDE", propName))
1007  {
1008  // crack the message
1009  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
1010  {
1011  const char * elemName = findXMLAttValu(ep, "name");
1012 
1013  if (!strcmp(elemName, "PIER_EAST") && !strcmp(pcdataXMLEle(ep), "On"))
1014  mountOTASide = -1;
1015  else if (!strcmp(elemName, "PIER_WEST") && !strcmp(pcdataXMLEle(ep), "On"))
1016  mountOTASide = 1;
1017  }
1018 
1019  return true;
1020  }
1021 
1022  controller->ISSnoopDevice(root);
1023 
1024  return DefaultDevice::ISSnoopDevice(root);
1025 }
1026 
1027 bool Dome::SetBacklash(int32_t steps)
1028 {
1029  INDI_UNUSED(steps);
1030  LOG_ERROR("Dome does not support backlash compensation.");
1031  return false;
1032 }
1033 
1034 bool Dome::SetBacklashEnabled(bool enabled)
1035 {
1036  // If disabled, set the Domeer backlash to zero.
1037  if (enabled)
1038  return SetBacklash(static_cast<int32_t>(DomeBacklashN[0].value));
1039  else
1040  return SetBacklash(0);
1041 }
1042 
1043 bool Dome::saveConfigItems(FILE * fp)
1044 {
1046 
1054 
1055  if (HasBacklash())
1056  {
1059  }
1060 
1061  if (HasShutter())
1062  {
1064  }
1065 
1066  controller->saveConfigItems(fp);
1067 
1068  return true;
1069 }
1070 
1071 void Dome::triggerSnoop(const char * driverName, const char * snoopedProp)
1072 {
1073  LOGF_DEBUG("Active Snoop, driver: %s, property: %s", driverName, snoopedProp);
1074  IDSnoopDevice(driverName, snoopedProp);
1075 }
1076 
1078 {
1079  return MountPolicyS[1].s == ISS_ON && IsLocked;
1080 }
1081 
1082 void Dome::buttonHelper(const char * button_n, ISState state, void * context)
1083 {
1084  static_cast<Dome *>(context)->processButton(button_n, state);
1085 }
1086 
1087 void Dome::processButton(const char * button_n, ISState state)
1088 {
1089  //ignore OFF
1090  if (state == ISS_OFF)
1091  return;
1092 
1093  // Dome In
1094  if (!strcmp(button_n, "Dome CW"))
1095  {
1096  if (DomeMotionSP.s != IPS_BUSY)
1098  else
1100  }
1101  else if (!strcmp(button_n, "Dome CCW"))
1102  {
1103  if (DomeMotionSP.s != IPS_BUSY)
1105  else
1107  }
1108  else if (!strcmp(button_n, "Dome Abort"))
1109  {
1110  Dome::Abort();
1111  }
1112 }
1113 
1115 {
1116  return m_MountState;
1117 }
1118 
1120 {
1121  switch (value)
1122  {
1123  case SHUTTER_OPENED:
1127  break;
1128 
1129  case SHUTTER_CLOSED:
1133  break;
1134 
1135 
1136  case SHUTTER_MOVING:
1138  break;
1139 
1140  case SHUTTER_ERROR:
1142  LOG_WARN("Shutter failure.");
1143  break;
1144 
1145  case SHUTTER_UNKNOWN:
1148  LOG_WARN("Unknown shutter status.");
1149  break;
1150  }
1151 
1152  IDSetSwitch(&DomeShutterSP, nullptr);
1153  m_ShutterState = value;
1154 }
1155 
1157 {
1158  switch (value)
1159  {
1160  case DOME_IDLE:
1161  if (DomeMotionSP.s == IPS_BUSY)
1162  {
1165  IDSetSwitch(&DomeMotionSP, nullptr);
1166  }
1167  if (DomeAbsPosNP.s == IPS_BUSY)
1168  {
1170  IDSetNumber(&DomeAbsPosNP, nullptr);
1171  }
1172  if (DomeRelPosNP.s == IPS_BUSY)
1173  {
1175  IDSetNumber(&DomeRelPosNP, nullptr);
1176  }
1177  break;
1178 
1179  case DOME_SYNCED:
1180  if (DomeMotionSP.s == IPS_BUSY)
1181  {
1183  DomeMotionSP.s = IPS_OK;
1184  IDSetSwitch(&DomeMotionSP, nullptr);
1185  }
1186  if (DomeAbsPosNP.s == IPS_BUSY)
1187  {
1188  DomeAbsPosNP.s = IPS_OK;
1189  IDSetNumber(&DomeAbsPosNP, nullptr);
1190  }
1191  if (DomeRelPosNP.s == IPS_BUSY)
1192  {
1193  DomeRelPosNP.s = IPS_OK;
1194  IDSetNumber(&DomeRelPosNP, nullptr);
1195  }
1196  break;
1197 
1198  case DOME_PARKED:
1199  if (DomeMotionSP.s == IPS_BUSY)
1200  {
1203  IDSetSwitch(&DomeMotionSP, nullptr);
1204  }
1205  if (DomeAbsPosNP.s == IPS_BUSY)
1206  {
1208  IDSetNumber(&DomeAbsPosNP, nullptr);
1209  }
1210  if (DomeRelPosNP.s == IPS_BUSY)
1211  {
1213  IDSetNumber(&DomeRelPosNP, nullptr);
1214  }
1216  ParkSP.s = IPS_OK;
1217  ParkS[0].s = ISS_ON;
1218  IDSetSwitch(&ParkSP, nullptr);
1219  IsParked = true;
1220  break;
1221 
1222  case DOME_PARKING:
1224  ParkSP.s = IPS_BUSY;
1225  ParkS[0].s = ISS_ON;
1226  IDSetSwitch(&ParkSP, nullptr);
1227  break;
1228 
1229  case DOME_UNPARKING:
1231  ParkSP.s = IPS_BUSY;
1232  ParkS[1].s = ISS_ON;
1233  IDSetSwitch(&ParkSP, nullptr);
1234  break;
1235 
1236  case DOME_UNPARKED:
1238  ParkSP.s = IPS_OK;
1239  ParkS[1].s = ISS_ON;
1240  IDSetSwitch(&ParkSP, nullptr);
1241  IsParked = false;
1242  break;
1243 
1244  case DOME_UNKNOWN:
1246  ParkSP.s = IPS_IDLE;
1247  IsParked = false;
1248  IDSetSwitch(&ParkSP, nullptr);
1249  break;
1250 
1251  case DOME_ERROR:
1252  ParkSP.s = IPS_ALERT;
1253  IDSetSwitch(&ParkSP, nullptr);
1254  break;
1255 
1256  case DOME_MOVING:
1257  break;
1258  }
1259 
1260  m_DomeState = value;
1261 }
1262 
1263 /*
1264 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.
1265 To do that we need to calculate the optical axis line taking the centre of the dome as origin of coordinates.
1266 */
1267 
1268 // Returns false if it can't solve it due bad geometry of the observatory
1269 // Returns:
1270 // Az : Azimuth required to the dome in order to center the shutter aperture with telescope
1271 // minAz: Minimum azimuth in order to avoid any dome interference to the full aperture of the telescope
1272 // maxAz: Maximum azimuth in order to avoid any dome interference to the full aperture of the telescope
1273 bool Dome::GetTargetAz(double &Az, double &Alt, double &minAz, double &maxAz)
1274 {
1275  point3D MountCenter, OptCenter, OptVector, DomeIntersect;
1276  double hourAngle;
1277  double mu1, mu2;
1278 
1279  if (HaveLatLong == false)
1280  {
1281  triggerSnoop(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
1282  LOG_WARN( "Geographic coordinates are not yet defined, triggering snoop...");
1283  return false;
1284  }
1285 
1286  double JD = ln_get_julian_from_sys();
1287  double MSD = ln_get_mean_sidereal_time(JD);
1288 
1289  LOGF_DEBUG("JD: %g - MSD: %g", JD, MSD);
1290 
1291  MountCenter.x = DomeMeasurementsN[DM_EAST_DISPLACEMENT].value; // Positive to East
1292  MountCenter.y = DomeMeasurementsN[DM_NORTH_DISPLACEMENT].value; // Positive to North
1293  MountCenter.z = DomeMeasurementsN[DM_UP_DISPLACEMENT].value; // Positive Up
1294 
1295  LOGF_DEBUG("MC.x: %g - MC.y: %g MC.z: %g", MountCenter.x, MountCenter.y, MountCenter.z);
1296 
1297  // Get hour angle in hours
1298  hourAngle = rangeHA( MSD + observer.longitude / 15.0 - mountEquatorialCoords.rightascension);
1299 
1300  LOGF_DEBUG("HA: %g Lng: %g RA: %g", hourAngle, observer.longitude, mountEquatorialCoords.rightascension);
1301 
1302  int OTASide = 0; // Side of the telescope with respect of the mount, 1: west, -1: east, 0: use the mid point
1303 
1304  if (OTASideSP.s == IPS_OK)
1305  {
1306  if(OTASideS[DM_OTA_SIDE_HA].s == ISS_ON || (UseHourAngle && OTASideS[DM_OTA_SIDE_MOUNT].s == ISS_ON))
1307  {
1308  // Note if the telescope points West, OTA is at east of the pier, and viceversa.
1309  if(hourAngle > 0)
1310  OTASide = -1;
1311  else
1312  OTASide = 1;
1313  }
1314  else if(OTASideS[DM_OTA_SIDE_EAST].s == ISS_ON)
1315  OTASide = -1;
1316  else if(OTASideS[DM_OTA_SIDE_WEST].s == ISS_ON)
1317  OTASide = 1;
1318  else if(OTASideS[DM_OTA_SIDE_MOUNT].s == ISS_ON)
1319  OTASide = mountOTASide;
1320 
1321  LOGF_DEBUG("OTA_SIDE selection: %d", IUFindOnSwitchIndex(&OTASideSP));
1322  }
1323 
1324  OpticalCenter(MountCenter, OTASide * DomeMeasurementsN[DM_OTA_OFFSET].value, observer.latitude, hourAngle, OptCenter);
1325 
1326  LOGF_DEBUG("OTA_SIDE: %d", OTASide);
1327  LOGF_DEBUG("Mount OTA_SIDE: %d", mountOTASide);
1328  LOGF_DEBUG("OTA_OFFSET: %g Lat: %g", DomeMeasurementsN[DM_OTA_OFFSET].value, observer.latitude);
1329  LOGF_DEBUG("OC.x: %g - OC.y: %g OC.z: %g", OptCenter.x, OptCenter.y, OptCenter.z);
1330 
1331  // To be sure mountHoriztonalCoords is up to date.
1333 
1334  // Get optical axis point. This and the previous form the optical axis line
1337  LOGF_DEBUG("OV.x: %g - OV.y: %g OV.z: %g", OptVector.x, OptVector.y, OptVector.z);
1338 
1339  if (Intersection(OptCenter, OptVector, DomeMeasurementsN[DM_DOME_RADIUS].value, mu1, mu2))
1340  {
1341  // If telescope is pointing over the horizon, the solution is mu1, else is mu2
1342  if (mu1 < 0)
1343  mu1 = mu2;
1344 
1345  double yx;
1346  double HalfApertureChordAngle;
1347  double RadiusAtAlt;
1348 
1349  DomeIntersect.x = OptCenter.x + mu1 * (OptVector.x );
1350  DomeIntersect.y = OptCenter.y + mu1 * (OptVector.y );
1351  DomeIntersect.z = OptCenter.z + mu1 * (OptVector.z );
1352 
1353  if (fabs(DomeIntersect.x) > 0.00001)
1354  {
1355  yx = DomeIntersect.y / DomeIntersect.x;
1356  Az = 90 - 180 * atan(yx) / M_PI;
1357  if (DomeIntersect.x < 0)
1358  {
1359  Az = Az + 180;
1360  }
1361  if (Az >= 360)
1362  Az -= 360;
1363  else if (Az < 0)
1364  Az += 360;
1365  }
1366  else
1367  {
1368  // Dome East-West line or zenith
1369  if (DomeIntersect.y > 0)
1370  Az = 90;
1371  else
1372  Az = 270;
1373  }
1374 
1375  if ((fabs(DomeIntersect.x) > 0.00001) || (fabs(DomeIntersect.y) > 0.00001))
1376  Alt = 180 *
1377  atan(DomeIntersect.z /
1378  sqrt((DomeIntersect.x * DomeIntersect.x) + (DomeIntersect.y * DomeIntersect.y))) /
1379  M_PI;
1380  else
1381  Alt = 90; // Dome Zenith
1382 
1383  // Calculate the Azimuth range in the given Altitude of the dome
1384  RadiusAtAlt = DomeMeasurementsN[DM_DOME_RADIUS].value * cos(M_PI * Alt / 180); // Radius alt the given altitude
1385 
1386  if (DomeMeasurementsN[DM_SHUTTER_WIDTH].value < (2 * RadiusAtAlt))
1387  {
1388  HalfApertureChordAngle = 180 * asin(DomeMeasurementsN[DM_SHUTTER_WIDTH].value / (2 * RadiusAtAlt)) /
1389  M_PI; // Angle of a chord of half aperture length
1390  minAz = Az - HalfApertureChordAngle;
1391  if (minAz < 0)
1392  minAz = minAz + 360;
1393  maxAz = Az + HalfApertureChordAngle;
1394  if (maxAz >= 360)
1395  maxAz = maxAz - 360;
1396  }
1397  else
1398  {
1399  minAz = 0;
1400  maxAz = 360;
1401  }
1402  return true;
1403  }
1404 
1405  return false;
1406 }
1407 
1408 bool Dome::Intersection(point3D p1, point3D dp, double r, double &mu1, double &mu2)
1409 {
1410  double a, b, c;
1411  double bb4ac;
1412 
1413  a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
1414  b = 2 * (dp.x * p1.x + dp.y * p1.y + dp.z * p1.z);
1415  c = 0.0;
1416  c = c + p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
1417  c = c - r * r;
1418  bb4ac = b * b - 4 * a * c;
1419  if ((fabs(a) < 0.0000001) || (bb4ac < 0))
1420  {
1421  mu1 = 0;
1422  mu2 = 0;
1423  return false;
1424  }
1425 
1426  mu1 = (-b + sqrt(bb4ac)) / (2 * a);
1427  mu2 = (-b - sqrt(bb4ac)) / (2 * a);
1428 
1429  return true;
1430 }
1431 
1432 bool Dome::OpticalCenter(point3D MountCenter, double dOpticalAxis, double Lat, double Ah, point3D &OP)
1433 {
1434  double q, f;
1435  double cosf, sinf, cosq, sinq;
1436 
1437  // Note: this transformation is a circle rotated around X axis -(90 - Lat) degrees
1438  q = M_PI * (90 - Lat) / 180;
1439  f = -M_PI * (180 + Ah * 15) / 180;
1440 
1441  cosf = cos(f);
1442  sinf = sin(f);
1443  cosq = cos(q);
1444  sinq = sin(q);
1445 
1446  OP.x = (dOpticalAxis * cosf + MountCenter.x); // The sign of dOpticalAxis determines de side of the tube
1447  OP.y = (dOpticalAxis * sinf * cosq + MountCenter.y);
1448  OP.z = (dOpticalAxis * sinf * sinq + MountCenter.z);
1449 
1450  return true;
1451 }
1452 
1453 bool Dome::OpticalVector(double Az, double Alt, point3D &OV)
1454 {
1455  double q, f;
1456 
1457  q = M_PI * Alt / 180;
1458  f = M_PI * Az / 180;
1459  OV.x = cos(q) * sin(f);
1460  OV.y = cos(q) * cos(f);
1461  OV.z = sin(q);
1462 
1463  return true;
1464 }
1465 
1466 double Dome::Csc(double x)
1467 {
1468  return 1.0 / sin(x);
1469 }
1470 
1471 double Dome::Sec(double x)
1472 {
1473  return 1.0 / cos(x);
1474 }
1475 
1476 bool Dome::CheckHorizon(double HA, double dec, double lat)
1477 {
1478  double sinh_value;
1479 
1480  sinh_value = cos(lat) * cos(HA) * cos(dec) + sin(lat) * sin(dec);
1481 
1482  if (sinh_value >= 0.0)
1483  return true;
1484 
1485  return false;
1486 }
1487 
1489 {
1490  // If not initialized yet, return.
1492  return;
1493 
1494  // Dont do this if we haven't had co-ordinates from the mount yet
1495  if (!HaveLatLong)
1496  return;
1497  if (!HaveRaDec)
1498  return;
1499 
1501 
1502  // Control debug flooding
1505  {
1508  LOGF_DEBUG("Updated telescope Az: %g - Alt: %g", prev_az, prev_alt);
1509  }
1510 
1511  // Check if we need to move if mount is unparked.
1512  if (IsMountParked == false)
1513  UpdateAutoSync();
1514 }
1515 
1517 {
1519  {
1520  if (CanPark())
1521  {
1522  if (isParked() == true)
1523  {
1524  if (AutoSyncWarning == false)
1525  {
1526  LOG_WARN("Cannot perform autosync with dome parked. Please unpark to enable autosync operation.");
1527  AutoSyncWarning = true;
1528  }
1529  return;
1530  }
1531  }
1532 
1533  AutoSyncWarning = false;
1534  double targetAz = 0, targetAlt = 0, minAz = 0, maxAz = 0;
1535  bool res;
1536  res = GetTargetAz(targetAz, targetAlt, minAz, maxAz);
1537  if (!res)
1538  {
1539  LOGF_DEBUG("GetTargetAz failed %g", targetAz);
1540  return;
1541  }
1542  LOGF_DEBUG("Calculated target azimuth is %.2f. MinAz: %.2f, MaxAz: %.2f", targetAz, minAz,
1543  maxAz);
1544 
1545  if (fabs(targetAz - DomeAbsPosN[0].value) > DomeParamN[0].value)
1546  {
1547  IPState ret = Dome::MoveAbs(targetAz);
1548  if (ret == IPS_OK)
1549  LOGF_DEBUG("Dome synced to position %.2f degrees.", targetAz);
1550  else if (ret == IPS_BUSY)
1551  LOGF_DEBUG("Dome is syncing to position %.2f degrees...", targetAz);
1552  else
1553  LOG_ERROR("Dome failed to sync to new requested position.");
1554 
1555  DomeAbsPosNP.s = ret;
1556  IDSetNumber(&DomeAbsPosNP, nullptr);
1557  }
1558  }
1559 }
1560 
1561 void Dome::SetDomeCapability(uint32_t cap)
1562 {
1563  capability = cap;
1564 
1565  if (CanAbort())
1566  controller->mapController("Dome Abort", "Dome Abort", Controller::CONTROLLER_BUTTON, "BUTTON_3");
1567 }
1568 
1570 {
1571  switch (status)
1572  {
1573  case SHUTTER_OPENED:
1574  return "Shutter is open.";
1575  case SHUTTER_CLOSED:
1576  return "Shutter is closed.";
1577  case SHUTTER_MOVING:
1578  return "Shutter is moving.";
1579  case SHUTTER_ERROR:
1580  return "Shutter has errors.";
1581  case SHUTTER_UNKNOWN:
1582  default:
1583  return "Shutter status is unknown.";
1584  }
1585 }
1586 
1588 {
1589  parkDataType = type;
1590 
1591  switch (parkDataType)
1592  {
1593  case PARK_NONE:
1594  strncpy(DomeMotionS[DOME_CW].label, "Open", MAXINDILABEL);
1595  strncpy(DomeMotionS[DOME_CCW].label, "Close", MAXINDILABEL);
1596  break;
1597 
1598  case PARK_AZ:
1599  IUFillNumber(&ParkPositionN[AXIS_AZ], "PARK_AZ", "AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0);
1600  IUFillNumberVector(&ParkPositionNP, ParkPositionN, 1, getDeviceName(), "DOME_PARK_POSITION", "Park Position",
1601  SITE_TAB, IP_RW, 60, IPS_IDLE);
1602  break;
1603 
1604  case PARK_AZ_ENCODER:
1605  IUFillNumber(&ParkPositionN[AXIS_AZ], "PARK_AZ", "AZ Encoder", "%.0f", 0, 16777215, 1, 0);
1606  IUFillNumberVector(&ParkPositionNP, ParkPositionN, 1, getDeviceName(), "DOME_PARK_POSITION", "Park Position",
1607  SITE_TAB, IP_RW, 60, IPS_IDLE);
1608  break;
1609 
1610  default:
1611  break;
1612  }
1613 }
1614 
1615 void Dome::SyncParkStatus(bool isparked)
1616 {
1617  IsParked = isparked;
1618 
1620 
1621  if (IsParked)
1622  {
1624  DEBUG(Logger::DBG_SESSION, "Dome is parked.");
1625  }
1626  else
1627  {
1629  DEBUG(Logger::DBG_SESSION, "Dome is unparked.");
1630  }
1631 }
1632 
1633 void Dome::SetParked(bool isparked)
1634 {
1635  SyncParkStatus(isparked);
1636  WriteParkData();
1637 }
1638 
1640 {
1641  return IsParked;
1642 }
1643 
1645 {
1646  const char * loadres = LoadParkData();
1647  if (loadres)
1648  {
1649  LOGF_INFO("InitPark: No Park data in file %s: %s", ParkDataFileName.c_str(), loadres);
1650  SyncParkStatus(false);
1651  return false;
1652  }
1653 
1654  SyncParkStatus(isParked());
1655 
1656  if (parkDataType != PARK_NONE)
1657  {
1658  LOGF_DEBUG("InitPark Axis1 %.2f", Axis1ParkPosition);
1659  ParkPositionN[AXIS_AZ].value = Axis1ParkPosition;
1660  IDSetNumber(&ParkPositionNP, nullptr);
1661 
1662  // If parked, store the position as current azimuth angle or encoder ticks
1663  if (isParked() && CanAbsMove())
1664  {
1665  DomeAbsPosN[0].value = ParkPositionN[AXIS_AZ].value;
1666  IDSetNumber(&DomeAbsPosNP, nullptr);
1667  }
1668  }
1669 
1670  return true;
1671 }
1672 
1673 const char * Dome::LoadParkXML()
1674 {
1675  wordexp_t wexp;
1676  FILE * fp;
1677  LilXML * lp;
1678  static char errmsg[512];
1679 
1680  XMLEle * parkxml;
1681  XMLAtt * ap;
1682  bool devicefound = false;
1683 
1684  ParkDeviceName = getDeviceName();
1685  ParkstatusXml = nullptr;
1686  ParkdeviceXml = nullptr;
1687  ParkpositionXml = nullptr;
1688  ParkpositionAxis1Xml = nullptr;
1689 
1690  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
1691  {
1692  wordfree(&wexp);
1693  return "Badly formed filename.";
1694  }
1695 
1696  if (!(fp = fopen(wexp.we_wordv[0], "r")))
1697  {
1698  wordfree(&wexp);
1699  return strerror(errno);
1700  }
1701  wordfree(&wexp);
1702 
1703  lp = newLilXML();
1704 
1705  if (ParkdataXmlRoot)
1706  delXMLEle(ParkdataXmlRoot);
1707 
1708  ParkdataXmlRoot = readXMLFile(fp, lp, errmsg);
1709  fclose(fp);
1710 
1711  delLilXML(lp);
1712  if (!ParkdataXmlRoot)
1713  return errmsg;
1714 
1715  if (!strcmp(tagXMLEle(nextXMLEle(ParkdataXmlRoot, 1)), "parkdata"))
1716  return "Not a park data file";
1717 
1718  parkxml = nextXMLEle(ParkdataXmlRoot, 1);
1719 
1720  while (parkxml)
1721  {
1722  if (strcmp(tagXMLEle(parkxml), "device"))
1723  {
1724  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
1725  continue;
1726  }
1727  ap = findXMLAtt(parkxml, "name");
1728  if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName)))
1729  {
1730  devicefound = true;
1731  break;
1732  }
1733  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
1734  }
1735 
1736  if (!devicefound)
1737  return "No park data found for this device";
1738 
1739  ParkdeviceXml = parkxml;
1740  ParkstatusXml = findXMLEle(parkxml, "parkstatus");
1741 
1742  if (parkDataType != PARK_NONE)
1743  {
1744  ParkpositionXml = findXMLEle(parkxml, "parkposition");
1745  ParkpositionAxis1Xml = findXMLEle(ParkpositionXml, "axis1position");
1746 
1747  if (ParkpositionAxis1Xml == nullptr)
1748  {
1749  return "Park position invalid or missing.";
1750  }
1751  }
1752  else if (ParkstatusXml == nullptr)
1753  return "Park status invalid or missing.";
1754 
1755  return nullptr;
1756 }
1757 
1758 const char * Dome::LoadParkData()
1759 {
1760  IsParked = false;
1761 
1762  const char * result = LoadParkXML();
1763  if (result != nullptr)
1764  return result;
1765 
1766  if (!strcmp(pcdataXMLEle(ParkstatusXml), "true"))
1767  IsParked = true;
1768 
1769  if (parkDataType == PARK_NONE)
1770  return nullptr;
1771 
1772  double axis1Pos = std::numeric_limits<double>::quiet_NaN();
1773 
1774  int rc = sscanf(pcdataXMLEle(ParkpositionAxis1Xml), "%lf", &axis1Pos);
1775  if (rc != 1)
1776  {
1777  return "Unable to parse Park Position Axis 1.";
1778  }
1779 
1780  if (std::isnan(axis1Pos) == false)
1781  {
1782  Axis1ParkPosition = axis1Pos;
1783  return nullptr;
1784  }
1785 
1786  return "Failed to parse Park Position.";
1787 }
1788 
1790 {
1791  // We need to refresh parking data in case other devices parking states were updated since we
1792  // read the data the first time.
1793  if (LoadParkXML() != nullptr)
1794  LOG_DEBUG("Failed to refresh parking data.");
1795 
1796  wordexp_t wexp;
1797  FILE * fp;
1798  char pcdata[30];
1799  ParkDeviceName = getDeviceName();
1800 
1801  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
1802  {
1803  wordfree(&wexp);
1804  LOGF_INFO("WriteParkData: can not write file %s: Badly formed filename.",
1805  ParkDataFileName.c_str());
1806  return false;
1807  }
1808 
1809  if (!(fp = fopen(wexp.we_wordv[0], "w")))
1810  {
1811  wordfree(&wexp);
1812  LOGF_INFO("WriteParkData: can not write file %s: %s", ParkDataFileName.c_str(),
1813  strerror(errno));
1814  return false;
1815  }
1816 
1817  if (!ParkdataXmlRoot)
1818  ParkdataXmlRoot = addXMLEle(nullptr, "parkdata");
1819 
1820  if (!ParkdeviceXml)
1821  {
1822  ParkdeviceXml = addXMLEle(ParkdataXmlRoot, "device");
1823  addXMLAtt(ParkdeviceXml, "name", ParkDeviceName);
1824  }
1825 
1826  if (!ParkstatusXml)
1827  ParkstatusXml = addXMLEle(ParkdeviceXml, "parkstatus");
1828  if (parkDataType != PARK_NONE)
1829  {
1830  if (!ParkpositionXml)
1831  ParkpositionXml = addXMLEle(ParkdeviceXml, "parkposition");
1832  if (!ParkpositionAxis1Xml)
1833  ParkpositionAxis1Xml = addXMLEle(ParkpositionXml, "axis1position");
1834  }
1835 
1836  editXMLEle(ParkstatusXml, (IsParked ? "true" : "false"));
1837 
1838  if (parkDataType != PARK_NONE)
1839  {
1840  snprintf(pcdata, sizeof(pcdata), "%lf", Axis1ParkPosition);
1841  editXMLEle(ParkpositionAxis1Xml, pcdata);
1842  }
1843 
1844  prXMLEle(fp, ParkdataXmlRoot, 0);
1845  fclose(fp);
1846  wordfree(&wexp);
1847 
1848  return true;
1849 }
1850 
1852 {
1853  return Axis1ParkPosition;
1854 }
1855 
1857 {
1858  return Axis1DefaultParkPosition;
1859 }
1860 
1861 void Dome::SetAxis1Park(double value)
1862 {
1863  Axis1ParkPosition = value;
1864  ParkPositionN[AXIS_RA].value = value;
1865  IDSetNumber(&ParkPositionNP, nullptr);
1866 }
1867 
1868 void Dome::SetAxis1ParkDefault(double value)
1869 {
1870  Axis1DefaultParkPosition = value;
1871 }
1872 
1874 {
1875  // Check if it is already parked.
1876  if (CanPark())
1877  {
1878  if (parkDataType != PARK_NONE && isParked())
1879  {
1880  LOG_WARN( "Please unpark the dome before issuing any motion commands.");
1881  return IPS_ALERT;
1882  }
1883  }
1884 
1885  if ((DomeMotionSP.s != IPS_BUSY && (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY)) ||
1887  {
1888  LOG_WARN( "Please stop dome before issuing any further motion commands.");
1889  return IPS_ALERT;
1890  }
1891 
1892  int current_direction = IUFindOnSwitchIndex(&DomeMotionSP);
1893 
1894  // if same move requested, return
1895  if (DomeMotionSP.s == IPS_BUSY && current_direction == dir && operation == MOTION_START)
1896  return IPS_BUSY;
1897 
1898  DomeMotionSP.s = Move(dir, operation);
1899 
1900  if (DomeMotionSP.s == IPS_BUSY || DomeMotionSP.s == IPS_OK)
1901  {
1902  m_DomeState = (operation == MOTION_START) ? DOME_MOVING : DOME_IDLE;
1904  if (operation == MOTION_START)
1905  DomeMotionS[dir].s = ISS_ON;
1906  }
1907 
1908  IDSetSwitch(&DomeMotionSP, nullptr);
1909 
1910  return DomeMotionSP.s;
1911 }
1912 
1913 IPState Dome::MoveRel(double azDiff)
1914 {
1915  if (CanRelMove() == false)
1916  {
1917  LOG_ERROR( "Dome does not support relative motion.");
1918  return IPS_ALERT;
1919  }
1920 
1921  if (m_DomeState == DOME_PARKED)
1922  {
1923  LOG_ERROR( "Please unpark before issuing any motion commands.");
1925  IDSetNumber(&DomeRelPosNP, nullptr);
1926  return IPS_ALERT;
1927  }
1928 
1930  {
1931  LOG_WARN( "Please stop dome before issuing any further motion commands.");
1933  IDSetNumber(&DomeRelPosNP, nullptr);
1934  return IPS_ALERT;
1935  }
1936 
1937  IPState rc;
1938 
1939  if ((rc = MoveRel(azDiff)) == IPS_OK)
1940  {
1942  DomeRelPosNP.s = IPS_OK;
1943  DomeRelPosN[0].value = azDiff;
1944  IDSetNumber(&DomeRelPosNP, "Dome moved %.2f degrees %s.", azDiff,
1945  (azDiff > 0) ? "clockwise" : "counter clockwise");
1946  if (CanAbsMove())
1947  {
1948  DomeAbsPosNP.s = IPS_OK;
1949  IDSetNumber(&DomeAbsPosNP, nullptr);
1950  }
1951  return IPS_OK;
1952  }
1953  else if (rc == IPS_BUSY)
1954  {
1956  DomeRelPosN[0].value = azDiff;
1958  IDSetNumber(&DomeRelPosNP, "Dome is moving %.2f degrees %s...", azDiff,
1959  (azDiff > 0) ? "clockwise" : "counter clockwise");
1960  if (CanAbsMove())
1961  {
1963  IDSetNumber(&DomeAbsPosNP, nullptr);
1964  }
1965 
1968  DomeMotionS[DOME_CW].s = (azDiff > 0) ? ISS_ON : ISS_OFF;
1969  DomeMotionS[DOME_CCW].s = (azDiff < 0) ? ISS_ON : ISS_OFF;
1970  IDSetSwitch(&DomeMotionSP, nullptr);
1971  return IPS_BUSY;
1972  }
1973 
1976  LOG_WARN("Dome failed to move to new requested position.");
1977  IDSetNumber(&DomeRelPosNP, nullptr);
1978  return IPS_ALERT;
1979 }
1980 
1982 {
1983  if (CanAbsMove() == false)
1984  {
1985  LOG_ERROR("Dome does not support MoveAbs(). MoveAbs() must be implemented in the child class.");
1986  return IPS_ALERT;
1987  }
1988 
1989  if (m_DomeState == DOME_PARKED)
1990  {
1991  LOG_ERROR( "Please unpark before issuing any motion commands.");
1993  IDSetNumber(&DomeAbsPosNP, nullptr);
1994  return IPS_ALERT;
1995  }
1996 
1998  {
1999  LOG_WARN( "Please stop dome before issuing any further motion commands.");
2000  return IPS_ALERT;
2001  }
2002 
2003  IPState rc;
2004 
2005  if (az < DomeAbsPosN[0].min || az > DomeAbsPosN[0].max)
2006  {
2007  LOGF_ERROR( "Error: requested azimuth angle %.2f is out of range.", az);
2009  IDSetNumber(&DomeAbsPosNP, nullptr);
2010  return IPS_ALERT;
2011  }
2012 
2013  if ((rc = MoveAbs(az)) == IPS_OK)
2014  {
2016  DomeAbsPosNP.s = IPS_OK;
2017  DomeAbsPosN[0].value = az;
2018  LOGF_INFO("Dome moved to position %.2f degrees azimuth.", az);
2019  IDSetNumber(&DomeAbsPosNP, nullptr);
2020 
2021  return IPS_OK;
2022  }
2023  else if (rc == IPS_BUSY)
2024  {
2027  LOGF_INFO("Dome is moving to position %.2f degrees azimuth...", az);
2028  IDSetNumber(&DomeAbsPosNP, nullptr);
2029 
2032  DomeMotionS[DOME_CW].s = (az > DomeAbsPosN[0].value) ? ISS_ON : ISS_OFF;
2033  DomeMotionS[DOME_CCW].s = (az < DomeAbsPosN[0].value) ? ISS_ON : ISS_OFF;
2034  IDSetSwitch(&DomeMotionSP, nullptr);
2035 
2036  return IPS_BUSY;
2037  }
2038 
2041  IDSetNumber(&DomeAbsPosNP, "Dome failed to move to new requested position.");
2042  return IPS_ALERT;
2043 }
2044 
2045 bool Dome::Sync(double az)
2046 {
2047  INDI_UNUSED(az);
2048  LOG_WARN("Syncing is not supported.");
2049  return false;
2050 }
2051 
2053 {
2054  if (CanAbort() == false)
2055  {
2056  LOG_ERROR( "Dome does not support abort.");
2057  return false;
2058  }
2059 
2061 
2062  if (Abort())
2063  {
2064  AbortSP.s = IPS_OK;
2065 
2067  {
2069  if (m_DomeState == DOME_PARKING)
2070  {
2071  DEBUG(Logger::DBG_SESSION, "Parking aborted.");
2072  // If parking was aborted then it was UNPARKED before
2073  ParkS[1].s = ISS_ON;
2074  }
2075  else
2076  {
2077  DEBUG(Logger::DBG_SESSION, "UnParking aborted.");
2078  // If unparking aborted then it was PARKED before
2079  ParkS[0].s = ISS_ON;
2080  }
2081 
2082  ParkSP.s = IPS_ALERT;
2083  IDSetSwitch(&ParkSP, nullptr);
2084  }
2085 
2087  }
2088  else
2089  {
2090  AbortSP.s = IPS_ALERT;
2091 
2092  // If alert was aborted during parking or unparking, the parking state is unknown
2094  {
2096  ParkSP.s = IPS_IDLE;
2097  IDSetSwitch(&ParkSP, nullptr);
2098  }
2099  }
2100 
2101  IDSetSwitch(&AbortSP, nullptr);
2102 
2103  return (AbortSP.s == IPS_OK);
2104 }
2105 
2106 bool Dome::SetSpeed(double speed)
2107 {
2108  if (HasVariableSpeed() == false)
2109  {
2110  LOG_ERROR( "Dome does not support variable speed.");
2111  return false;
2112  }
2113 
2114  if (SetSpeed(speed))
2115  {
2116  DomeSpeedNP.s = IPS_OK;
2117  DomeSpeedN[0].value = speed;
2118  }
2119  else
2121 
2122  IDSetNumber(&DomeSpeedNP, nullptr);
2123 
2124  return (DomeSpeedNP.s == IPS_OK);
2125 }
2126 
2128 {
2129  if (HasShutter() == false)
2130  {
2131  LOG_ERROR( "Dome does not have shutter control.");
2132  return IPS_ALERT;
2133  }
2134 
2135  // if (weatherState == IPS_ALERT && operation == SHUTTER_OPEN)
2136  // {
2137  // LOG_WARN( "Weather is in the danger zone! Cannot open shutter.");
2138  // return IPS_ALERT;
2139  // }
2140 
2141  int currentStatus = IUFindOnSwitchIndex(&DomeShutterSP);
2142 
2143  // No change of status, let's return
2144  if (DomeShutterSP.s == IPS_BUSY && currentStatus == operation)
2145  {
2146  IDSetSwitch(&DomeShutterSP, nullptr);
2147  return DomeShutterSP.s;
2148  }
2149 
2150  DomeShutterSP.s = ControlShutter(operation);
2151 
2152  if (DomeShutterSP.s == IPS_OK)
2153  {
2154  IDSetSwitch(&DomeShutterSP, "Shutter is %s.", (operation == SHUTTER_OPEN ? "open" : "closed"));
2156  return DomeShutterSP.s;
2157  }
2158  else if (DomeShutterSP.s == IPS_BUSY)
2159  {
2161  DomeShutterS[operation].s = ISS_ON;
2162  IDSetSwitch(&DomeShutterSP, "Shutter is %s...", (operation == 0 ? "opening" : "closing"));
2164  return DomeShutterSP.s;
2165  }
2166 
2167  IDSetSwitch(&DomeShutterSP, "Shutter failed to %s.", (operation == 0 ? "open" : "close"));
2168  return IPS_ALERT;
2169 }
2170 
2172 {
2173  // Not really supposed to get this at all, but just in case.
2174  if (CanPark() == false)
2175  {
2176  LOG_ERROR( "Dome does not support parking.");
2177  return IPS_ALERT;
2178  }
2179 
2180  // No need to park if parked already.
2181  if (m_DomeState == DOME_PARKED)
2182  {
2184  ParkS[0].s = ISS_ON;
2185  LOG_INFO("Dome already parked.");
2186  IDSetSwitch(&ParkSP, nullptr);
2187  return IPS_OK;
2188  }
2189 
2190  // Check if dome is locked due to Mount Policy
2191  if (isLocked())
2192  {
2194  ParkS[1].s = ISS_ON;
2195  ParkSP.s = IPS_ALERT;
2196  IDSetSwitch(&ParkSP, nullptr);
2197  LOG_INFO("Cannot Park Dome when mount is locking. See: Mount Policy in options tab.");
2198  return IPS_ALERT;
2199  }
2200 
2201  // Now ask child driver to start the actual parking process.
2202  ParkSP.s = Park();
2203 
2204  // IPS_OK is when it is immediately parked so realisticly this does not happen
2205  // unless dome is physically parked but just needed a state change.
2206  if (ParkSP.s == IPS_OK)
2207  SetParked(true);
2208  // Dome is moving to parking position
2209  else if (ParkSP.s == IPS_BUSY)
2210  {
2212 
2213  if (CanAbsMove())
2215 
2217  ParkS[0].s = ISS_ON;
2218  }
2219  else
2220  IDSetSwitch(&ParkSP, nullptr);
2221 
2222  return ParkSP.s;
2223 }
2224 
2226 {
2227  if (CanPark() == false)
2228  {
2229  LOG_ERROR( "Dome does not support parking.");
2230  return IPS_ALERT;
2231  }
2232 
2233  if (m_DomeState != DOME_PARKED)
2234  {
2236  ParkS[1].s = ISS_ON;
2237  DEBUG(Logger::DBG_SESSION, "Dome already unparked.");
2238  IDSetSwitch(&ParkSP, nullptr);
2239  return IPS_OK;
2240  }
2241 
2242  // if (weatherState == IPS_ALERT)
2243  // {
2244  // LOG_WARN( "Weather is in the danger zone! Cannot unpark dome.");
2245  // ParkSP.s = IPS_OK;
2246  // IDSetSwitch(&ParkSP, nullptr);
2247  // return IPS_ALERT;
2248  // }
2249 
2250  ParkSP.s = UnPark();
2251 
2252  if (ParkSP.s == IPS_OK)
2253  SetParked(false);
2254  else if (ParkSP.s == IPS_BUSY)
2256  else
2257  IDSetSwitch(&ParkSP, nullptr);
2258 
2259  return ParkSP.s;
2260 }
2261 
2263 {
2264  LOG_WARN( "Parking is not supported.");
2265  return false;
2266 }
2267 
2269 {
2270  LOG_WARN( "Parking is not supported.");
2271  return false;
2272 }
2273 
2275 {
2276  return false;
2277 }
2278 
2279 bool Dome::callHandshake()
2280 {
2281  if (domeConnection > 0)
2282  {
2285  else if (getActiveConnection() == tcpConnection)
2287  }
2288 
2289  return Handshake();
2290 }
2291 
2293 {
2294  return domeConnection;
2295 }
2296 
2297 void Dome::setDomeConnection(const uint8_t &value)
2298 {
2300 
2301  if (value == 0 || (mask & value) == 0)
2302  {
2303  LOGF_ERROR( "Invalid connection mode %d", value);
2304  return;
2305  }
2306 
2307  domeConnection = value;
2308 }
2309 
2310 }
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:1232
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:1861
INDI::Dome::DM_OTA_SIDE_EAST
@ DM_OTA_SIDE_EAST
Definition: indidome.h:595
INDI::Dome::Park
virtual IPState Park()
Goto Park Position. The park position is an absolute azimuth value.
Definition: indidome.cpp:2171
INDI::Dome::DOME_PARKED
@ DOME_PARKED
Definition: indidome.h:136
INDI::Dome::SHUTTER_CLOSE_ON_PARK
@ SHUTTER_CLOSE_ON_PARK
Definition: indidome.h:578
INDI::Dome::PresetGotoS
ISwitch PresetGotoS[3]
Definition: indidome.h:584
INDI::Dome::DM_OTA_SIDE_HA
@ DM_OTA_SIDE_HA
Definition: indidome.h:598
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:120
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:1475
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:1027
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:2225
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:1587
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
INDI::Dome::DM_OTA_SIDE_IGNORE
@ DM_OTA_SIDE_IGNORE
Definition: indidome.h:599
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:1981
_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:1873
INDI::Controller::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
Definition: indicontroller.cpp:302
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:1432
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:1082
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:2106
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:201
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:1453
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:1466
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:2268
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:1043
INDI::Dome::isLocked
bool isLocked()
isLocked, is the dome currently locked?
Definition: indidome.cpp:1077
INDI::Dome::MoveRel
virtual IPState MoveRel(double azDiff)
Move the Dome to an relative position.
Definition: indidome.cpp:1913
INDI::Dome::DomeDirection
DomeDirection
Definition: indidome.h:91
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:2052
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:1488
INDI::Dome::setDomeState
void setDomeState(const DomeState &value)
Definition: indidome.cpp:1156
INDI::Dome::GetTargetAz
bool GetTargetAz(double &Az, double &Alt, double &minAz, double &maxAz)
GetTargetAz.
Definition: indidome.cpp:1273
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:1455
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:1442
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:1414
INDI::Dome::GetAxis1Park
double GetAxis1Park()
Definition: indidome.cpp:1851
INDI::Dome::DomeBacklashSP
ISwitchVectorProperty DomeBacklashSP
Definition: indidome.h:607
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_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:2292
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:1460
ra
double ra
Definition: ieqprolegacydriver.cpp:43
INDI::Dome::CONNECTION_SERIAL
@ CONNECTION_SERIAL
Definition: indidome.h:172
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:2127
INDI::IGeographicCoordinates::latitude
double latitude
Definition: libastro.h:67
INDI::Dome::DM_OTA_SIDE_MOUNT
@ DM_OTA_SIDE_MOUNT
Definition: indidome.h:597
INDI::Dome::GetShutterStatusString
const char * GetShutterStatusString(ShutterState status)
getShutterStatusString
Definition: indidome.cpp:1569
INDI::Dome::LoadParkData
const char * LoadParkData()
Definition: indidome.cpp:1758
INDI::Dome::SetBacklashEnabled
virtual bool SetBacklashEnabled(bool enabled)
SetBacklashEnabled Enables or disables the dome backlash compensation.
Definition: indidome.cpp:1034
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::Dome::SHUTTER_OPEN_ON_UNPARK
@ SHUTTER_OPEN_ON_UNPARK
Definition: indidome.h:579
INDI::BaseDevice::DOME_INTERFACE
@ DOME_INTERFACE
Definition: basedevice.h:77
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
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:1868
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:1114
_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:1856
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:1639
INDI::Dome::WriteParkData
bool WriteParkData()
Definition: indidome.cpp:1789
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:1119
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::Dome::CheckHorizon
bool CheckHorizon(double HA, double dec, double lat)
CheckHorizon Returns true if telescope points above horizon.
Definition: indidome.cpp:1476
INDI::Dome::CONNECTION_TCP
@ CONNECTION_TCP
Definition: indidome.h:173
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
name
const char * name
Definition: indiserver.c:116
INDI::Dome::SetParked
void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: indidome.cpp:1633
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:1408
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::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:2045
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::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:137
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:1471
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:1644
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:2297
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:1561
INDI::Controller::initProperties
virtual bool initProperties()
Definition: indicontroller.cpp:109
INDI::Dome::PARK_AZ_ENCODER
@ PARK_AZ_ENCODER
Definition: indidome.h:107
INDI::Dome::DM_OTA_SIDE_WEST
@ DM_OTA_SIDE_WEST
Definition: indidome.h:596
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:1424
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:1465
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:2262
errno
int errno
INDI::Controller::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Definition: indicontroller.cpp:183
INDI::Dome::CONNECTION_NONE
@ CONNECTION_NONE
Definition: indidome.h:171
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:2274
INDI::Dome::PortFD
int PortFD
Definition: indidome.h:617
INDI::BaseDevice::INDI_DISABLED
@ INDI_DISABLED
Definition: basedevice.h:65
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:1516
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151