Instrument Neutral Distributed Interface INDI  1.9.5
inditelescope.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "inditelescope.h"
20 
21 #include "indicom.h"
22 #include "indicontroller.h"
25 
26 #include <libnova/sidereal_time.h>
27 #include <libnova/transform.h>
28 
29 #include <cmath>
30 #include <cerrno>
31 #include <pwd.h>
32 #include <cstdlib>
33 #include <cstring>
34 #include <ctime>
35 #include <unistd.h>
36 #include <wordexp.h>
37 #include <limits>
38 
39 namespace INDI
40 {
41 
43  : DefaultDevice(), ScopeConfigFileName(GetHomeDirectory() + "/.indi/ScopeConfig.xml"),
44  ParkDataFileName(GetHomeDirectory() + "/.indi/ParkData.xml")
45 {
46  controller = new Controller(this);
47  controller->setJoystickCallback(joystickHelper);
48  controller->setAxisCallback(axisHelper);
49  controller->setButtonCallback(buttonHelper);
50 
51  currentPierSide = PIER_EAST;
52  lastPierSide = PIER_UNKNOWN;
53 
54  currentPECState = PEC_OFF;
55  lastPECState = PEC_UNKNOWN;
56 }
57 
59 {
60  if (ParkdataXmlRoot)
61  delXMLEle(ParkdataXmlRoot);
62 
63  delete (controller);
64 }
65 
67 {
69 
70  // Active Devices
71  IUFillText(&ActiveDeviceT[0], "ACTIVE_GPS", "GPS", "GPS Simulator");
72  IUFillText(&ActiveDeviceT[1], "ACTIVE_DOME", "DOME", "Dome Simulator");
73  IUFillTextVector(&ActiveDeviceTP, ActiveDeviceT, 2, getDeviceName(), "ACTIVE_DEVICES", "Snoop devices", OPTIONS_TAB,
74  IP_RW, 60, IPS_IDLE);
75 
76  // Use locking if dome is closed (and or) park scope if dome is closing
77  IUFillSwitch(&DomePolicyS[DOME_IGNORED], "DOME_IGNORED", "Dome ignored", ISS_ON);
78  IUFillSwitch(&DomePolicyS[DOME_LOCKS], "DOME_LOCKS", "Dome locks", ISS_OFF);
79  // IUFillSwitch(&DomeClosedLockT[2], "FORCE_CLOSE", "Dome parks", ISS_OFF);
80  // IUFillSwitch(&DomeClosedLockT[3], "LOCK_AND_FORCE", "Both", ISS_OFF);
81  IUFillSwitchVector(&DomePolicySP, DomePolicyS, 2, getDeviceName(), "DOME_POLICY", "Dome Policy", OPTIONS_TAB, IP_RW,
83 
84  IUFillNumber(&EqN[AXIS_RA], "RA", "RA (hh:mm:ss)", "%010.6m", 0, 24, 0, 0);
85  IUFillNumber(&EqN[AXIS_DE], "DEC", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
86  IUFillNumberVector(&EqNP, EqN, 2, getDeviceName(), "EQUATORIAL_EOD_COORD", "Eq. Coordinates", MAIN_CONTROL_TAB,
87  IP_RW, 60, IPS_IDLE);
88  lastEqState = IPS_IDLE;
89 
90  IUFillNumber(&TargetN[AXIS_RA], "RA", "RA (hh:mm:ss)", "%010.6m", 0, 24, 0, 0);
91  IUFillNumber(&TargetN[AXIS_DE], "DEC", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
92  IUFillNumberVector(&TargetNP, TargetN, 2, getDeviceName(), "TARGET_EOD_COORD", "Slew Target", MOTION_TAB, IP_RO, 60,
93  IPS_IDLE);
94 
95  IUFillSwitch(&ParkOptionS[PARK_CURRENT], "PARK_CURRENT", "Current", ISS_OFF);
96  IUFillSwitch(&ParkOptionS[PARK_DEFAULT], "PARK_DEFAULT", "Default", ISS_OFF);
97  IUFillSwitch(&ParkOptionS[PARK_WRITE_DATA], "PARK_WRITE_DATA", "Write Data", ISS_OFF);
98  IUFillSwitch(&ParkOptionS[PARK_PURGE_DATA], "PARK_PURGE_DATA", "Purge Data", ISS_OFF);
99  IUFillSwitchVector(&ParkOptionSP, ParkOptionS, 4, getDeviceName(), "TELESCOPE_PARK_OPTION", "Park Options",
101 
102  IUFillText(&TimeT[0], "UTC", "UTC Time", nullptr);
103  IUFillText(&TimeT[1], "OFFSET", "UTC Offset", nullptr);
104  IUFillTextVector(&TimeTP, TimeT, 2, getDeviceName(), "TIME_UTC", "UTC", SITE_TAB, IP_RW, 60, IPS_IDLE);
105 
106  IUFillNumber(&LocationN[LOCATION_LATITUDE], "LAT", "Lat (dd:mm:ss.s)", "%012.8m", -90, 90, 0, 0.0);
107  IUFillNumber(&LocationN[LOCATION_LONGITUDE], "LONG", "Lon (dd:mm:ss.s)", "%012.8m", 0, 360, 0, 0.0);
108  IUFillNumber(&LocationN[LOCATION_ELEVATION], "ELEV", "Elevation (m)", "%g", -200, 10000, 0, 0);
109  IUFillNumberVector(&LocationNP, LocationN, 3, getDeviceName(), "GEOGRAPHIC_COORD", "Scope Location", SITE_TAB,
110  IP_RW, 60, IPS_IDLE);
111 
112  // Pier Side
113  IUFillSwitch(&PierSideS[PIER_WEST], "PIER_WEST", "West (pointing east)", ISS_OFF);
114  IUFillSwitch(&PierSideS[PIER_EAST], "PIER_EAST", "East (pointing west)", ISS_OFF);
115  IUFillSwitchVector(&PierSideSP, PierSideS, 2, getDeviceName(), "TELESCOPE_PIER_SIDE", "Pier Side", MAIN_CONTROL_TAB,
116  IP_RO, ISR_ATMOST1, 60, IPS_IDLE);
117  // Pier Side Simulation
118  IUFillSwitch(&SimulatePierSideS[0], "SIMULATE_YES", "Yes", ISS_OFF);
119  IUFillSwitch(&SimulatePierSideS[1], "SIMULATE_NO", "No", ISS_ON);
120  IUFillSwitchVector(&SimulatePierSideSP, SimulatePierSideS, 2, getDeviceName(), "SIMULATE_PIER_SIDE", "Simulate Pier Side",
122  IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
123 
124  // PEC State
125  IUFillSwitch(&PECStateS[PEC_OFF], "PEC OFF", "PEC OFF", ISS_ON);
126  IUFillSwitch(&PECStateS[PEC_ON], "PEC ON", "PEC ON", ISS_OFF);
127  IUFillSwitchVector(&PECStateSP, PECStateS, 2, getDeviceName(), "PEC", "PEC Playback", MOTION_TAB, IP_RW, ISR_1OFMANY, 0,
128  IPS_IDLE);
129 
130  // Track Mode. Child class must call AddTrackMode to add members
131  IUFillSwitchVector(&TrackModeSP, TrackModeS, 0, getDeviceName(), "TELESCOPE_TRACK_MODE", "Track Mode", MAIN_CONTROL_TAB,
132  IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
133 
134  // Track State
135  IUFillSwitch(&TrackStateS[TRACK_ON], "TRACK_ON", "On", ISS_OFF);
136  IUFillSwitch(&TrackStateS[TRACK_OFF], "TRACK_OFF", "Off", ISS_ON);
137  IUFillSwitchVector(&TrackStateSP, TrackStateS, 2, getDeviceName(), "TELESCOPE_TRACK_STATE", "Tracking", MAIN_CONTROL_TAB,
138  IP_RW, ISR_1OFMANY, 0,
139  IPS_IDLE);
140 
141  // Track Rate
142  IUFillNumber(&TrackRateN[AXIS_RA], "TRACK_RATE_RA", "RA (arcsecs/s)", "%.6f", -16384.0, 16384.0, 0.000001,
144  IUFillNumber(&TrackRateN[AXIS_DE], "TRACK_RATE_DE", "DE (arcsecs/s)", "%.6f", -16384.0, 16384.0, 0.000001, 0.0);
145  IUFillNumberVector(&TrackRateNP, TrackRateN, 2, getDeviceName(), "TELESCOPE_TRACK_RATE", "Track Rates", MAIN_CONTROL_TAB,
146  IP_RW, 60, IPS_IDLE);
147 
148  // On Coord Set actions
149  IUFillSwitch(&CoordS[0], "TRACK", "Track", ISS_ON);
150  IUFillSwitch(&CoordS[1], "SLEW", "Slew", ISS_OFF);
151  IUFillSwitch(&CoordS[2], "SYNC", "Sync", ISS_OFF);
152 
153  // If both GOTO and SYNC are supported
154  if (CanGOTO() && CanSync())
155  IUFillSwitchVector(&CoordSP, CoordS, 3, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
156  ISR_1OFMANY, 60, IPS_IDLE);
157  // If ONLY GOTO is supported
158  else if (CanGOTO())
159  IUFillSwitchVector(&CoordSP, CoordS, 2, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
160  ISR_1OFMANY, 60, IPS_IDLE);
161  // If ONLY SYNC is supported
162  else if (CanSync())
163  {
164  IUFillSwitch(&CoordS[0], "SYNC", "Sync", ISS_ON);
165  IUFillSwitchVector(&CoordSP, CoordS, 1, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
166  ISR_1OFMANY, 60, IPS_IDLE);
167  }
168 
169  if (nSlewRate >= 4)
170  IUFillSwitchVector(&SlewRateSP, SlewRateS, nSlewRate, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate",
172 
173  if (CanTrackSatellite())
174  {
175  IUFillText(&TLEtoTrackT[0], "TLE", "TLE", "");
176  IUFillTextVector(&TLEtoTrackTP, TLEtoTrackT, 1, getDeviceName(), "SAT_TLE_TEXT", "Orbit Params", SATELLITE_TAB,
177  IP_RW, 60, IPS_IDLE);
178 
179  char curTime[32] = {0};
180  std::time_t t = std::time(nullptr);
181  struct std::tm *utctimeinfo = std::gmtime(&t);
182  strftime(curTime, sizeof(curTime), "%Y-%m-%dT%H:%M:%S", utctimeinfo);
183 
184  IUFillText(&SatPassWindowT[SAT_PASS_WINDOW_END], "SAT_PASS_WINDOW_END", "End UTC", curTime);
185  IUFillText(&SatPassWindowT[SAT_PASS_WINDOW_START], "SAT_PASS_WINDOW_START", "Start UTC", curTime);
187  "SAT_PASS_WINDOW", "Pass Window", SATELLITE_TAB, IP_RW, 60, IPS_IDLE);
188 
189  IUFillSwitch(&TrackSatS[SAT_TRACK], "SAT_TRACK", "Track", ISS_OFF);
190  IUFillSwitch(&TrackSatS[SAT_HALT], "SAT_HALT", "Halt", ISS_ON);
192  "Sat tracking", SATELLITE_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
193  }
194 
195  IUFillSwitch(&ParkS[0], "PARK", "Park(ed)", ISS_OFF);
196  IUFillSwitch(&ParkS[1], "UNPARK", "UnPark(ed)", ISS_OFF);
197  IUFillSwitchVector(&ParkSP, ParkS, 2, getDeviceName(), "TELESCOPE_PARK", "Parking", MAIN_CONTROL_TAB, IP_RW,
198  ISR_1OFMANY, 60, IPS_IDLE);
199 
200  IUFillSwitch(&AbortS[0], "ABORT", "Abort", ISS_OFF);
201  IUFillSwitchVector(&AbortSP, AbortS, 1, getDeviceName(), "TELESCOPE_ABORT_MOTION", "Abort Motion", MAIN_CONTROL_TAB,
202  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
203 
204  IUFillSwitch(&MovementNSS[DIRECTION_NORTH], "MOTION_NORTH", "North", ISS_OFF);
205  IUFillSwitch(&MovementNSS[DIRECTION_SOUTH], "MOTION_SOUTH", "South", ISS_OFF);
206  IUFillSwitchVector(&MovementNSSP, MovementNSS, 2, getDeviceName(), "TELESCOPE_MOTION_NS", "Motion N/S", MOTION_TAB,
207  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
208 
209  IUFillSwitch(&MovementWES[DIRECTION_WEST], "MOTION_WEST", "West", ISS_OFF);
210  IUFillSwitch(&MovementWES[DIRECTION_EAST], "MOTION_EAST", "East", ISS_OFF);
211  IUFillSwitchVector(&MovementWESP, MovementWES, 2, getDeviceName(), "TELESCOPE_MOTION_WE", "Motion W/E", MOTION_TAB,
212  IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
213 
214  IUFillNumber(&ScopeParametersN[0], "TELESCOPE_APERTURE", "Aperture (mm)", "%g", 10, 5000, 0, 0.0);
215  IUFillNumber(&ScopeParametersN[1], "TELESCOPE_FOCAL_LENGTH", "Focal Length (mm)", "%g", 10, 10000, 0, 0.0);
216  IUFillNumber(&ScopeParametersN[2], "GUIDER_APERTURE", "Guider Aperture (mm)", "%g", 10, 5000, 0, 0.0);
217  IUFillNumber(&ScopeParametersN[3], "GUIDER_FOCAL_LENGTH", "Guider Focal Length (mm)", "%g", 10, 10000, 0, 0.0);
218  IUFillNumberVector(&ScopeParametersNP, ScopeParametersN, 4, getDeviceName(), "TELESCOPE_INFO", "Scope Properties",
219  OPTIONS_TAB, IP_RW, 60, IPS_OK);
220 
221  // Scope config name
222  IUFillText(&ScopeConfigNameT[0], "SCOPE_CONFIG_NAME", "Config Name", "");
223  IUFillTextVector(&ScopeConfigNameTP, ScopeConfigNameT, 1, getDeviceName(), "SCOPE_CONFIG_NAME", "Scope Name",
224  OPTIONS_TAB, IP_RW, 60, IPS_OK);
225 
226  // Switch for aperture/focal length configs
227  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG1], "SCOPE_CONFIG1", "Config #1", ISS_ON);
228  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG2], "SCOPE_CONFIG2", "Config #2", ISS_OFF);
229  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG3], "SCOPE_CONFIG3", "Config #3", ISS_OFF);
230  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG4], "SCOPE_CONFIG4", "Config #4", ISS_OFF);
231  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG5], "SCOPE_CONFIG5", "Config #5", ISS_OFF);
232  IUFillSwitch(&ScopeConfigs[SCOPE_CONFIG6], "SCOPE_CONFIG6", "Config #6", ISS_OFF);
233  IUFillSwitchVector(&ScopeConfigsSP, ScopeConfigs, 6, getDeviceName(), "APPLY_SCOPE_CONFIG", "Scope Configs",
235 
236  controller->initProperties();
237 
238  // Joystick motion control
239  IUFillSwitch(&MotionControlModeT[0], "MOTION_CONTROL_MODE_JOYSTICK", "4-Way Joystick", ISS_ON);
240  IUFillSwitch(&MotionControlModeT[1], "MOTION_CONTROL_MODE_AXES", "Two Separate Axes", ISS_OFF);
241  IUFillSwitchVector(&MotionControlModeTP, MotionControlModeT, 2, getDeviceName(), "MOTION_CONTROL_MODE", "Motion Control",
242  "Joystick", IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
243 
244  // Lock Axis
245  IUFillSwitch(&LockAxisS[0], "LOCK_AXIS_1", "West/East", ISS_OFF);
246  IUFillSwitch(&LockAxisS[1], "LOCK_AXIS_2", "North/South", ISS_OFF);
247  IUFillSwitchVector(&LockAxisSP, LockAxisS, 2, getDeviceName(), "JOYSTICK_LOCK_AXIS", "Lock Axis", "Joystick", IP_RW,
248  ISR_ATMOST1, 60, IPS_IDLE);
249 
251 
253 
254  if (telescopeConnection & CONNECTION_SERIAL)
255  {
258  {
259  return callHandshake();
260  });
262  }
263 
264  if (telescopeConnection & CONNECTION_TCP)
265  {
266  tcpConnection = new Connection::TCP(this);
268  {
269  return callHandshake();
270  });
271 
273  }
274 
275  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
276  IDSnoopDevice(ActiveDeviceT[0].text, "TIME_UTC");
277 
278  IDSnoopDevice(ActiveDeviceT[1].text, "DOME_PARK");
279  IDSnoopDevice(ActiveDeviceT[1].text, "DOME_SHUTTER");
280 
282 
283  double longitude = 0, latitude = 0, elevation = 0;
284  // Get value from config file if it exists.
286  {
287  LocationN[LOCATION_LONGITUDE].value = longitude;
288  m_Location.longitude = longitude;
289  }
291  {
292  LocationN[LOCATION_LATITUDE].value = latitude;
293  m_Location.latitude = latitude;
294  }
296  {
297  LocationN[LOCATION_ELEVATION].value = elevation;
298  m_Location.elevation = elevation;
299  }
300 
301  return true;
302 }
303 
304 void Telescope::ISGetProperties(const char *dev)
305 {
306  // First we let our parent populate
308 
309  if (CanGOTO())
310  {
312  loadConfig(true, "ACTIVE_DEVICES");
313 
314  ISState isDomeIgnored = ISS_OFF;
315  if (IUGetConfigSwitch(getDeviceName(), DomePolicySP.name, DomePolicyS[DOME_IGNORED].name, &isDomeIgnored) == 0)
316  {
317  DomePolicyS[DOME_IGNORED].s = isDomeIgnored;
318  DomePolicyS[DOME_LOCKS].s = (isDomeIgnored == ISS_ON) ? ISS_OFF : ISS_ON;
319  }
321  }
322 
325 
326  if (HasDefaultScopeConfig())
327  {
328  LoadScopeConfig();
329  }
330  else
331  {
332  loadConfig(true, "TELESCOPE_INFO");
333  loadConfig(true, "SCOPE_CONFIG_NAME");
334  }
335 
336  if (CanGOTO())
337  controller->ISGetProperties(dev);
338 }
339 
341 {
342  if (isConnected())
343  {
344  controller->mapController("MOTIONDIR", "N/S/W/E Control", Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1");
345  controller->mapController("MOTIONDIRNS", "N/S Control", Controller::CONTROLLER_AXIS, "AXIS_8");
346  controller->mapController("MOTIONDIRWE", "W/E Control", Controller::CONTROLLER_AXIS, "AXIS_7");
347 
348  if (nSlewRate >= 4)
349  {
350  controller->mapController("SLEWPRESET", "Slew Rate", Controller::CONTROLLER_JOYSTICK, "JOYSTICK_2");
351  controller->mapController("SLEWPRESETUP", "Slew Rate Up", Controller::CONTROLLER_BUTTON, "BUTTON_5");
352  controller->mapController("SLEWPRESETDOWN", "Slew Rate Down", Controller::CONTROLLER_BUTTON,
353  "BUTTON_6");
354  }
355  if (CanAbort())
356  controller->mapController("ABORTBUTTON", "Abort", Controller::CONTROLLER_BUTTON, "BUTTON_1");
357  if (CanPark())
358  {
359  controller->mapController("PARKBUTTON", "Park", Controller::CONTROLLER_BUTTON, "BUTTON_2");
360  controller->mapController("UNPARKBUTTON", "UnPark", Controller::CONTROLLER_BUTTON, "BUTTON_3");
361  }
362 
363  // Now we add our telescope specific stuff
364  if (CanGOTO() || CanSync())
367  if (CanAbort())
369 
370  if (HasTrackMode() && TrackModeS != nullptr)
372  if (CanControlTrack())
374  if (HasTrackRate())
376 
377 
378  if (CanGOTO())
379  {
382  if (nSlewRate >= 4)
385  }
386 
387  if (HasTime())
389  if (HasLocation())
391  if (CanPark())
392  {
394  if (parkDataType != PARK_NONE)
395  {
398  }
399  }
400 
401  if (HasPierSide())
403 
404  if (HasPierSideSimulation())
405  {
407  ISState value;
408  if (IUGetConfigSwitch(getDefaultName(), "SIMULATE_PIER_SIDE", "SIMULATE_YES", &value) )
409  setSimulatePierSide(value == ISS_ON);
410  }
411 
412  if (CanTrackSatellite())
413  {
417  }
418 
419  if (HasPECState())
421 
424  }
425  else
426  {
427  if (CanGOTO() || CanSync())
430  if (CanAbort())
432  if (HasTrackMode() && TrackModeS != nullptr)
434  if (HasTrackRate())
436  if (CanControlTrack())
438 
439  if (CanGOTO())
440  {
443  if (nSlewRate >= 4)
446  }
447 
448  if (HasTime())
450  if (HasLocation())
452 
453  if (CanPark())
454  {
456  if (parkDataType != PARK_NONE)
457  {
460  }
461  }
462 
463  if (HasPierSide())
465 
466  if (HasPierSideSimulation())
467  {
469  if (getSimulatePierSide() == true)
471  }
472 
473  if (CanTrackSatellite())
474  {
478  }
479 
480  if (HasPECState())
482 
485  }
486 
487  if (CanGOTO())
488  {
489  controller->updateProperties();
490 
491  ISwitchVectorProperty *useJoystick = getSwitch("USEJOYSTICK");
492  if (useJoystick)
493  {
494  if (isConnected())
495  {
496  if (useJoystick->sp[0].s == ISS_ON)
497  {
499  loadConfig(true, "MOTION_CONTROL_MODE");
501  loadConfig(true, "LOCK_AXIS");
502  }
503  else
504  {
507  }
508  }
509  else
510  {
513  }
514  }
515  }
516 
517  return true;
518 }
519 
521 {
522  controller->ISSnoopDevice(root);
523 
524  XMLEle *ep = nullptr;
525  const char *propName = findXMLAttValu(root, "name");
526 
527  if (isConnected())
528  {
529  if (HasLocation() && !strcmp(propName, "GEOGRAPHIC_COORD"))
530  {
531  // Only accept IPS_OK state
532  if (strcmp(findXMLAttValu(root, "state"), "Ok"))
533  return false;
534 
535  double longitude = -1, latitude = -1, elevation = -1;
536 
537  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
538  {
539  const char *elemName = findXMLAttValu(ep, "name");
540 
541  if (!strcmp(elemName, "LAT"))
542  latitude = atof(pcdataXMLEle(ep));
543  else if (!strcmp(elemName, "LONG"))
544  longitude = atof(pcdataXMLEle(ep));
545  else if (!strcmp(elemName, "ELEV"))
546  elevation = atof(pcdataXMLEle(ep));
547  }
548 
549  return processLocationInfo(latitude, longitude, elevation);
550  }
551  else if (HasTime() && !strcmp(propName, "TIME_UTC"))
552  {
553  // Only accept IPS_OK state
554  if (strcmp(findXMLAttValu(root, "state"), "Ok"))
555  return false;
556 
557  char utc[MAXINDITSTAMP], offset[MAXINDITSTAMP];
558 
559  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
560  {
561  const char *elemName = findXMLAttValu(ep, "name");
562 
563  if (!strcmp(elemName, "UTC"))
564  strncpy(utc, pcdataXMLEle(ep), MAXINDITSTAMP);
565  else if (!strcmp(elemName, "OFFSET"))
566  strncpy(offset, pcdataXMLEle(ep), MAXINDITSTAMP);
567  }
568 
569  return processTimeInfo(utc, offset);
570  }
571  else if (!strcmp(propName, "DOME_PARK")/* || !strcmp(propName, "DOME_SHUTTER")*/)
572  {
573  // This is handled by Watchdog driver.
574  // Mount shouldn't park due to dome closing in INDI::Telescope
575 #if 0
576  if (strcmp(findXMLAttValu(root, "state"), "Ok"))
577  {
578  // Dome options is dome parks or both and dome is parking.
579  if ((DomeClosedLockT[2].s == ISS_ON || DomeClosedLockT[3].s == ISS_ON) && !IsLocked && !IsParked)
580  {
581  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
582  {
583  const char * elemName = findXMLAttValu(ep, "name");
584  if (( (!strcmp(elemName, "SHUTTER_CLOSE") || !strcmp(elemName, "PARK"))
585  && !strcmp(pcdataXMLEle(ep), "On")))
586  {
588  Park();
589  LOG_INFO("Dome is closing, parking mount...");
590  }
591  }
592  }
593  } // Dome is changing state and Dome options is lock or both. d
594  else
595 #endif
596  if (!strcmp(findXMLAttValu(root, "state"), "Ok"))
597  {
598  bool prevState = IsLocked;
599  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
600  {
601  const char *elemName = findXMLAttValu(ep, "name");
602 
603  if (!IsLocked && (!strcmp(elemName, "PARK")) && !strcmp(pcdataXMLEle(ep), "On"))
604  IsLocked = true;
605  else if (IsLocked && (!strcmp(elemName, "UNPARK")) && !strcmp(pcdataXMLEle(ep), "On"))
606  IsLocked = false;
607  }
608  if (prevState != IsLocked && (DomePolicyS[DOME_LOCKS].s == ISS_ON))
609  LOGF_INFO("Dome status changed. Lock is set to: %s", IsLocked ? "locked" : "unlock");
610  }
611  return true;
612  }
613  }
614 
615  return DefaultDevice::ISSnoopDevice(root);
616 }
617 
618 void Telescope::triggerSnoop(const char *driverName, const char *snoopedProp)
619 {
620  LOGF_DEBUG("Active Snoop, driver: %s, property: %s", driverName, snoopedProp);
621  IDSnoopDevice(driverName, snoopedProp);
622 }
623 
624 uint8_t Telescope::getTelescopeConnection() const
625 {
626  return telescopeConnection;
627 }
628 
629 void Telescope::setTelescopeConnection(const uint8_t &value)
630 {
632 
633  if (value == 0 || (mask & value) == 0)
634  {
635  DEBUGF(Logger::DBG_ERROR, "Invalid connection mode %d", value);
636  return;
637  }
638 
639  telescopeConnection = value;
640 }
641 
642 bool Telescope::saveConfigItems(FILE *fp)
643 {
645 
648 
649  // Ensure that we only save valid locations
650  if (HasLocation() && (LocationN[LOCATION_LONGITUDE].value != 0 || LocationN[LOCATION_LATITUDE].value != 0))
652 
653  if (!HasDefaultScopeConfig())
654  {
655  if (ScopeParametersNP.s == IPS_OK)
657  if (ScopeConfigNameTP.s == IPS_OK)
659  }
660  if (SlewRateS != nullptr)
662  if (HasPECState())
664  if (HasTrackMode())
666  if (HasTrackRate())
668 
669  controller->saveConfigItems(fp);
673 
674  return true;
675 }
676 
677 void Telescope::NewRaDec(double ra, double dec)
678 {
679  switch (TrackState)
680  {
681  case SCOPE_PARKED:
682  case SCOPE_IDLE:
683  EqNP.s = IPS_IDLE;
684  break;
685 
686  case SCOPE_SLEWING:
687  case SCOPE_PARKING:
688  EqNP.s = IPS_BUSY;
689  break;
690 
691  case SCOPE_TRACKING:
692  EqNP.s = IPS_OK;
693  break;
694  }
695 
697  {
701  IDSetSwitch(&TrackStateSP, nullptr);
702  }
704  {
708  IDSetSwitch(&TrackStateSP, nullptr);
709  }
710 
711  if (EqN[AXIS_RA].value != ra || EqN[AXIS_DE].value != dec || EqNP.s != lastEqState)
712  {
713  EqN[AXIS_RA].value = ra;
714  EqN[AXIS_DE].value = dec;
715  lastEqState = EqNP.s;
716  IDSetNumber(&EqNP, nullptr);
717  }
718 }
719 
720 bool Telescope::Sync(double ra, double dec)
721 {
722  INDI_UNUSED(ra);
723  INDI_UNUSED(dec);
724  // if we get here, our mount doesn't support sync
725  DEBUG(Logger::DBG_ERROR, "Telescope does not support Sync.");
726  return false;
727 }
728 
729 bool Telescope::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command)
730 {
731  INDI_UNUSED(dir);
732  INDI_UNUSED(command);
733  DEBUG(Logger::DBG_ERROR, "Telescope does not support North/South motion.");
737  return false;
738 }
739 
740 bool Telescope::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command)
741 {
742  INDI_UNUSED(dir);
743  INDI_UNUSED(command);
744  DEBUG(Logger::DBG_ERROR, "Telescope does not support West/East motion.");
747  IDSetSwitch(&MovementWESP, nullptr);
748  return false;
749 }
750 
751 /**************************************************************************************
752 ** Process Text properties
753 ***************************************************************************************/
754 bool Telescope::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
755 {
756  // first check if it's for our device
757  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
758  {
759  if (!strcmp(name, TimeTP.name))
760  {
761  int utcindex = IUFindIndex("UTC", names, n);
762  int offsetindex = IUFindIndex("OFFSET", names, n);
763 
764  return processTimeInfo(texts[utcindex], texts[offsetindex]);
765  }
766 
767  if (!strcmp(name, ActiveDeviceTP.name))
768  {
770  IUUpdateText(&ActiveDeviceTP, texts, names, n);
771  // Update client display
772  IDSetText(&ActiveDeviceTP, nullptr);
773 
774  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
775  IDSnoopDevice(ActiveDeviceT[0].text, "TIME_UTC");
776 
777  IDSnoopDevice(ActiveDeviceT[1].text, "DOME_PARK");
778  IDSnoopDevice(ActiveDeviceT[1].text, "DOME_SHUTTER");
779  return true;
780  }
781 
782  if (name && std::string(name) == "SCOPE_CONFIG_NAME")
783  {
785  IUUpdateText(&ScopeConfigNameTP, texts, names, n);
786  IDSetText(&ScopeConfigNameTP, nullptr);
788  return true;
789  }
790  }
791 
792  controller->ISNewText(dev, name, texts, names, n);
793 
794  return DefaultDevice::ISNewText(dev, name, texts, names, n);
795 }
796 
797 /**************************************************************************************
798 **
799 ***************************************************************************************/
800 bool Telescope::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
801 {
802  // first check if it's for our device
803  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
804  {
806  // Goto & Sync for Equatorial Coords
808  if (strcmp(name, "EQUATORIAL_EOD_COORD") == 0)
809  {
810  // this is for us, and it is a goto
811  bool rc = false;
812  double ra = -1;
813  double dec = -100;
814 
815  for (int x = 0; x < n; x++)
816  {
817  INumber *eqp = IUFindNumber(&EqNP, names[x]);
818  if (eqp == &EqN[AXIS_RA])
819  {
820  ra = values[x];
821  }
822  else if (eqp == &EqN[AXIS_DE])
823  {
824  dec = values[x];
825  }
826  }
827  if ((ra >= 0) && (ra <= 24) && (dec >= -90) && (dec <= 90))
828  {
829  // Check if it is already parked.
830  if (CanPark())
831  {
832  if (isParked())
833  {
835  "Please unpark the mount before issuing any motion/sync commands.");
836  EqNP.s = lastEqState = IPS_IDLE;
837  IDSetNumber(&EqNP, nullptr);
838  return false;
839  }
840  }
841 
842  // Check if it can sync
843  if (CanSync())
844  {
845  ISwitch *sw;
846  sw = IUFindSwitch(&CoordSP, "SYNC");
847  if ((sw != nullptr) && (sw->s == ISS_ON))
848  {
849  rc = Sync(ra, dec);
850  if (rc)
851  EqNP.s = lastEqState = IPS_OK;
852  else
853  EqNP.s = lastEqState = IPS_ALERT;
854  IDSetNumber(&EqNP, nullptr);
855  return rc;
856  }
857  }
858 
859  // Remember Track State
861  // Issue GOTO
862  rc = Goto(ra, dec);
863  if (rc)
864  {
865  EqNP.s = lastEqState = IPS_BUSY;
866  // Now fill in target co-ords, so domes can start turning
867  TargetN[AXIS_RA].value = ra;
868  TargetN[AXIS_DE].value = dec;
869  IDSetNumber(&TargetNP, nullptr);
870  }
871  else
872  {
873  EqNP.s = lastEqState = IPS_ALERT;
874  }
875  IDSetNumber(&EqNP, nullptr);
876  }
877  return rc;
878  }
879 
881  // Geographic Coords
883  if (strcmp(name, "GEOGRAPHIC_COORD") == 0)
884  {
885  int latindex = IUFindIndex("LAT", names, n);
886  int longindex = IUFindIndex("LONG", names, n);
887  int elevationindex = IUFindIndex("ELEV", names, n);
888 
889  if (latindex == -1 || longindex == -1 || elevationindex == -1)
890  {
892  IDSetNumber(&LocationNP, "Location data missing or corrupted.");
893  }
894 
895  double targetLat = values[latindex];
896  double targetLong = values[longindex];
897  double targetElev = values[elevationindex];
898 
899  return processLocationInfo(targetLat, targetLong, targetElev);
900  }
901 
903  // Telescope Info
905  if (strcmp(name, "TELESCOPE_INFO") == 0)
906  {
908 
909  IUUpdateNumber(&ScopeParametersNP, values, names, n);
910  IDSetNumber(&ScopeParametersNP, nullptr);
912  return true;
913  }
914 
916  // Park Position
918  if (strcmp(name, ParkPositionNP.name) == 0)
919  {
920  double axis1 = std::numeric_limits<double>::quiet_NaN(), axis2 = std::numeric_limits<double>::quiet_NaN();
921  for (int x = 0; x < n; x++)
922  {
923  INumber *parkPosAxis = IUFindNumber(&ParkPositionNP, names[x]);
924  if (parkPosAxis == &ParkPositionN[AXIS_RA])
925  {
926  axis1 = values[x];
927  }
928  else if (parkPosAxis == &ParkPositionN[AXIS_DE])
929  {
930  axis2 = values[x];
931  }
932  }
933 
934  if (std::isnan(axis1) == false && std::isnan(axis2) == false)
935  {
936  bool rc = false;
937 
938  rc = SetParkPosition(axis1, axis2);
939 
940  if (rc)
941  {
942  IUUpdateNumber(&ParkPositionNP, values, names, n);
943  Axis1ParkPosition = ParkPositionN[AXIS_RA].value;
944  Axis2ParkPosition = ParkPositionN[AXIS_DE].value;
945  }
946 
947  ParkPositionNP.s = rc ? IPS_OK : IPS_ALERT;
948  }
949  else
951 
952  IDSetNumber(&ParkPositionNP, nullptr);
953  return true;
954  }
955 
957  // Track Rate
959  if (strcmp(name, TrackRateNP.name) == 0)
960  {
961  double preAxis1 = TrackRateN[AXIS_RA].value, preAxis2 = TrackRateN[AXIS_DE].value;
962  bool rc = (IUUpdateNumber(&TrackRateNP, values, names, n) == 0);
963 
964  if (!rc)
965  {
967  IDSetNumber(&TrackRateNP, nullptr);
968  return false;
969  }
970 
971  if (TrackState == SCOPE_TRACKING && !strcmp(IUFindOnSwitch(&TrackModeSP)->name, "TRACK_CUSTOM"))
972  {
973  // Check that we do not abruplty change positive tracking rates to negative ones.
974  // tracking must be stopped first.
975  // Give warning is tracking sign would cause a reverse in direction
976  if ( (preAxis1 * TrackRateN[AXIS_RA].value < 0) || (preAxis2 * TrackRateN[AXIS_DE].value < 0) )
977  {
978  LOG_ERROR("Cannot reverse tracking while tracking is engaged. Disengage tracking then try again.");
979  return false;
980  }
981 
982  // All is fine, ask mount to change tracking rate
983  rc = SetTrackRate(TrackRateN[AXIS_RA].value, TrackRateN[AXIS_DE].value);
984 
985  if (!rc)
986  {
987  TrackRateN[AXIS_RA].value = preAxis1;
988  TrackRateN[AXIS_DE].value = preAxis2;
989  }
990  }
991 
992  // If we are already tracking but tracking mode is NOT custom
993  // We just inform the user that it must be set to custom for these values to take
994  // effect.
995  if (TrackState == SCOPE_TRACKING && strcmp(IUFindOnSwitch(&TrackModeSP)->name, "TRACK_CUSTOM"))
996  {
997  LOG_INFO("Custom tracking rates set. Tracking mode must be set to Custom for these rates to take effect.");
998  }
999 
1000  // If mount is NOT tracking, we simply accept whatever valid values for use when mount tracking is engaged.
1001  TrackRateNP.s = rc ? IPS_OK : IPS_ALERT;
1002  IDSetNumber(&TrackRateNP, nullptr);
1003  return true;
1004  }
1005  }
1006 
1007  return DefaultDevice::ISNewNumber(dev, name, values, names, n);
1008 }
1009 
1010 /**************************************************************************************
1011 **
1012 ***************************************************************************************/
1013 bool Telescope::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
1014 {
1015  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
1016  {
1017  // This one is for us
1018  if (!strcmp(name, CoordSP.name))
1019  {
1020  // client is telling us what to do with co-ordinate requests
1021  CoordSP.s = IPS_OK;
1022  IUUpdateSwitch(&CoordSP, states, names, n);
1023  // Update client display
1024  IDSetSwitch(&CoordSP, nullptr);
1025  return true;
1026  }
1027 
1029  // Slew Rate
1031  if (!strcmp(name, SlewRateSP.name))
1032  {
1033  int preIndex = IUFindOnSwitchIndex(&SlewRateSP);
1034  IUUpdateSwitch(&SlewRateSP, states, names, n);
1035  int nowIndex = IUFindOnSwitchIndex(&SlewRateSP);
1036  if (SetSlewRate(nowIndex) == false)
1037  {
1039  SlewRateS[preIndex].s = ISS_ON;
1041  }
1042  else
1043  SlewRateSP.s = IPS_OK;
1044  IDSetSwitch(&SlewRateSP, nullptr);
1045  return true;
1046  }
1047 
1049  // Parking
1051  if (!strcmp(name, ParkSP.name))
1052  {
1053  if (TrackState == SCOPE_PARKING)
1054  {
1056  ParkSP.s = IPS_ALERT;
1057  Abort();
1058  LOG_INFO("Parking/Unparking aborted.");
1059  IDSetSwitch(&ParkSP, nullptr);
1060  return true;
1061  }
1062 
1063  int preIndex = IUFindOnSwitchIndex(&ParkSP);
1064  IUUpdateSwitch(&ParkSP, states, names, n);
1065 
1066  bool toPark = (ParkS[0].s == ISS_ON);
1067 
1068  if (toPark == false && TrackState != SCOPE_PARKED)
1069  {
1071  ParkS[1].s = ISS_ON;
1072  ParkSP.s = IPS_IDLE;
1073  LOG_INFO("Telescope already unparked.");
1074  IsParked = false;
1075  IDSetSwitch(&ParkSP, nullptr);
1076  return true;
1077  }
1078 
1079  if (toPark == false && isLocked())
1080  {
1082  ParkS[0].s = ISS_ON;
1083  ParkSP.s = IPS_ALERT;
1084  LOG_WARN("Cannot unpark mount when dome is locking. See: Dome Policy in options tab.");
1085  IsParked = true;
1086  IDSetSwitch(&ParkSP, nullptr);
1087  return true;
1088  }
1089 
1090  if (toPark && TrackState == SCOPE_PARKED)
1091  {
1093  ParkS[0].s = ISS_ON;
1094  ParkSP.s = IPS_IDLE;
1095  LOG_INFO("Telescope already parked.");
1096  IDSetSwitch(&ParkSP, nullptr);
1097  return true;
1098  }
1099 
1101 
1103  bool rc = toPark ? Park() : UnPark();
1104  if (rc)
1105  {
1106  if (TrackState == SCOPE_PARKING)
1107  {
1108  ParkS[0].s = toPark ? ISS_ON : ISS_OFF;
1109  ParkS[1].s = toPark ? ISS_OFF : ISS_ON;
1110  ParkSP.s = IPS_BUSY;
1111  }
1112  else
1113  {
1114  ParkS[0].s = toPark ? ISS_ON : ISS_OFF;
1115  ParkS[1].s = toPark ? ISS_OFF : ISS_ON;
1116  ParkSP.s = IPS_OK;
1117  }
1118  }
1119  else
1120  {
1121  ParkS[preIndex].s = ISS_ON;
1122  ParkSP.s = IPS_ALERT;
1123  }
1124 
1125  IDSetSwitch(&ParkSP, nullptr);
1126  return true;
1127  }
1128 
1130  // NS Motion
1132  if (!strcmp(name, MovementNSSP.name))
1133  {
1134  // Check if it is already parked.
1135  if (CanPark())
1136  {
1137  if (isParked())
1138  {
1140  "Please unpark the mount before issuing any motion/sync commands.");
1142  IDSetSwitch(&MovementNSSP, nullptr);
1143  return false;
1144  }
1145  }
1146 
1147  IUUpdateSwitch(&MovementNSSP, states, names, n);
1148 
1149  int current_motion = IUFindOnSwitchIndex(&MovementNSSP);
1150 
1151  // if same move requested, return
1152  if (MovementNSSP.s == IPS_BUSY && current_motion == last_ns_motion)
1153  return true;
1154 
1155  // Time to stop motion
1156  if (current_motion == -1 || (last_ns_motion != -1 && current_motion != last_ns_motion))
1157  {
1159  {
1162  last_ns_motion = -1;
1163  // Update Target when stopped so that domes can track
1164  TargetN[AXIS_RA].value = EqN[AXIS_RA].value;
1165  TargetN[AXIS_DE].value = EqN[AXIS_DE].value;
1166  IDSetNumber(&TargetNP, nullptr);
1167  }
1168  else
1170  }
1171  else
1172  {
1175 
1176  if (MoveNS(current_motion == 0 ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_START))
1177  {
1179  last_ns_motion = current_motion;
1180  }
1181  else
1182  {
1185  last_ns_motion = -1;
1186  }
1187  }
1188 
1189  IDSetSwitch(&MovementNSSP, nullptr);
1190 
1191  return true;
1192  }
1193 
1195  // WE Motion
1197  if (!strcmp(name, MovementWESP.name))
1198  {
1199  // Check if it is already parked.
1200  if (CanPark())
1201  {
1202  if (isParked())
1203  {
1205  "Please unpark the mount before issuing any motion/sync commands.");
1207  IDSetSwitch(&MovementWESP, nullptr);
1208  return false;
1209  }
1210  }
1211 
1212  IUUpdateSwitch(&MovementWESP, states, names, n);
1213 
1214  int current_motion = IUFindOnSwitchIndex(&MovementWESP);
1215 
1216  // if same move requested, return
1217  if (MovementWESP.s == IPS_BUSY && current_motion == last_we_motion)
1218  return true;
1219 
1220  // Time to stop motion
1221  if (current_motion == -1 || (last_we_motion != -1 && current_motion != last_we_motion))
1222  {
1224  {
1227  last_we_motion = -1;
1228  // Update Target when stopped so that domes can track
1229  TargetN[AXIS_RA].value = EqN[AXIS_RA].value;
1230  TargetN[AXIS_DE].value = EqN[AXIS_DE].value;
1231  IDSetNumber(&TargetNP, nullptr);
1232  }
1233  else
1235  }
1236  else
1237  {
1240 
1241  if (MoveWE(current_motion == 0 ? DIRECTION_WEST : DIRECTION_EAST, MOTION_START))
1242  {
1244  last_we_motion = current_motion;
1245  }
1246  else
1247  {
1250  last_we_motion = -1;
1251  }
1252  }
1253 
1254  IDSetSwitch(&MovementWESP, nullptr);
1255 
1256  return true;
1257  }
1258 
1260  // Abort Motion
1262  if (!strcmp(name, AbortSP.name))
1263  {
1265 
1266  if (Abort())
1267  {
1268  AbortSP.s = IPS_OK;
1269 
1270  if (ParkSP.s == IPS_BUSY)
1271  {
1273  ParkSP.s = IPS_ALERT;
1274  IDSetSwitch(&ParkSP, nullptr);
1275 
1276  LOG_INFO("Parking aborted.");
1277  }
1278  if (EqNP.s == IPS_BUSY)
1279  {
1280  EqNP.s = lastEqState = IPS_IDLE;
1281  IDSetNumber(&EqNP, nullptr);
1282  LOG_INFO("Slew/Track aborted.");
1283  }
1284  if (MovementWESP.s == IPS_BUSY)
1285  {
1288  IDSetSwitch(&MovementWESP, nullptr);
1289  }
1290  if (MovementNSSP.s == IPS_BUSY)
1291  {
1294  IDSetSwitch(&MovementNSSP, nullptr);
1295  }
1296 
1298 
1299  // JM 2017-07-28: Abort shouldn't affect tracking state. It should affect motion and that's it.
1300  //if (TrackState != SCOPE_PARKED)
1301  //TrackState = SCOPE_IDLE;
1302  // For Idle, Tracking, Parked state, we do not change its status, it should remain as is.
1303  // For Slewing & Parking, state should go back to last rememberd state.
1305  {
1307  }
1308  }
1309  else
1310  AbortSP.s = IPS_ALERT;
1311 
1312  IDSetSwitch(&AbortSP, nullptr);
1313 
1314  return true;
1315  }
1316 
1318  // Track Mode
1320  if (!strcmp(name, TrackModeSP.name))
1321  {
1322  int prevIndex = IUFindOnSwitchIndex(&TrackModeSP);
1323  IUUpdateSwitch(&TrackModeSP, states, names, n);
1324  int currIndex = IUFindOnSwitchIndex(&TrackModeSP);
1325  // If same as previous index, or if scope is already idle, then just update switch and return. No commands are sent to the mount.
1326  if (prevIndex == currIndex || TrackState == SCOPE_IDLE)
1327  {
1328  TrackModeSP.s = IPS_OK;
1329  IDSetSwitch(&TrackModeSP, nullptr);
1330  return true;
1331  }
1332 
1333  if (TrackState == SCOPE_PARKED)
1334  {
1335  DEBUG(Logger::DBG_WARNING, "Telescope is Parked, Unpark before changing track mode.");
1336  return false;
1337  }
1338 
1339  bool rc = SetTrackMode(currIndex);
1340  if (rc)
1341  TrackModeSP.s = IPS_OK;
1342  else
1343  {
1345  TrackModeS[prevIndex].s = ISS_ON;
1347  }
1348  IDSetSwitch(&TrackModeSP, nullptr);
1349  return false;
1350  }
1351 
1353  // Track State
1355  if (!strcmp(name, TrackStateSP.name))
1356  {
1357  int previousState = IUFindOnSwitchIndex(&TrackStateSP);
1358  IUUpdateSwitch(&TrackStateSP, states, names, n);
1359  int targetState = IUFindOnSwitchIndex(&TrackStateSP);
1360 
1361  if (previousState == targetState)
1362  {
1363  IDSetSwitch(&TrackStateSP, nullptr);
1364  return true;
1365  }
1366 
1367  if (TrackState == SCOPE_PARKED)
1368  {
1369  DEBUG(Logger::DBG_WARNING, "Telescope is Parked, Unpark before tracking.");
1370  return false;
1371  }
1372 
1373  bool rc = SetTrackEnabled((targetState == TRACK_ON) ? true : false);
1374 
1375  if (rc)
1376  {
1377  TrackState = (targetState == TRACK_ON) ? SCOPE_TRACKING : SCOPE_IDLE;
1378 
1379  TrackStateSP.s = (targetState == TRACK_ON) ? IPS_BUSY : IPS_IDLE;
1380 
1381  TrackStateS[TRACK_ON].s = (targetState == TRACK_ON) ? ISS_ON : ISS_OFF;
1382  TrackStateS[TRACK_OFF].s = (targetState == TRACK_ON) ? ISS_OFF : ISS_ON;
1383  }
1384  else
1385  {
1388  TrackStateS[previousState].s = ISS_ON;
1389  }
1390 
1391  IDSetSwitch(&TrackStateSP, nullptr);
1392  return true;
1393  }
1394 
1396  // Park Options
1398  if (!strcmp(name, ParkOptionSP.name))
1399  {
1400  IUUpdateSwitch(&ParkOptionSP, states, names, n);
1401  int index = IUFindOnSwitchIndex(&ParkOptionSP);
1402  if (index == -1)
1403  return false;
1404 
1406 
1407  bool rc = false;
1408 
1410  MovementWESP.s == IPS_BUSY)
1411  {
1412  LOG_INFO("Can not change park position while slewing or already parked...");
1414  IDSetSwitch(&ParkOptionSP, nullptr);
1415  return false;
1416  }
1417 
1418  switch (index)
1419  {
1420  case PARK_CURRENT:
1421  rc = SetCurrentPark();
1422  break;
1423  case PARK_DEFAULT:
1424  rc = SetDefaultPark();
1425  break;
1426  case PARK_WRITE_DATA:
1427  rc = WriteParkData();
1428  if (rc)
1429  LOG_INFO("Saved Park Status/Position.");
1430  else
1431  DEBUG(Logger::DBG_WARNING, "Can not save Park Status/Position.");
1432  break;
1433  case PARK_PURGE_DATA:
1434  rc = PurgeParkData();
1435  if (rc)
1436  LOG_INFO("Park data purged.");
1437  else
1438  DEBUG(Logger::DBG_WARNING, "Can not purge Park Status/Position.");
1439  break;
1440  }
1441 
1442  ParkOptionSP.s = rc ? IPS_OK : IPS_ALERT;
1443  IDSetSwitch(&ParkOptionSP, nullptr);
1444 
1445  return true;
1446  }
1447 
1449  // Parking Dome Policy
1451  if (!strcmp(name, DomePolicySP.name))
1452  {
1453  IUUpdateSwitch(&DomePolicySP, states, names, n);
1454  if (DomePolicyS[DOME_IGNORED].s == ISS_ON)
1455  LOG_INFO("Dome Policy set to: Dome ignored. Mount can park or unpark regardless of dome parking state.");
1456  else
1457  LOG_WARN("Dome Policy set to: Dome locks. This prevents the mount from unparking when dome is parked.");
1458 #if 0
1459  else if (!strcmp(names[0], DomeClosedLockT[2].name))
1460  LOG_INFO("Warning: Dome parking policy set to: Dome parks. This tells "
1461  "scope to park if dome is parking. This will disable the locking "
1462  "for dome parking, EVEN IF MOUNT PARKING FAILS");
1463  else if (!strcmp(names[0], DomeClosedLockT[3].name))
1464  LOG_INFO("Warning: Dome parking policy set to: Both. This disallows the "
1465  "scope from unparking when dome is parked, and tells scope to "
1466  "park if dome is parking. This will disable the locking for dome "
1467  "parking, EVEN IF MOUNT PARKING FAILS.");
1468 #endif
1469  DomePolicySP.s = IPS_OK;
1470  IDSetSwitch(&DomePolicySP, nullptr);
1471  triggerSnoop(ActiveDeviceT[1].text, "DOME_PARK");
1472  return true;
1473  }
1474 
1476  // Simulate Pier Side
1477  // This ia a major change to the design of the simulated scope, it might not handle changes on the fly
1479  if (!strcmp(name, SimulatePierSideSP.name))
1480  {
1481  IUUpdateSwitch(&SimulatePierSideSP, states, names, n);
1483  if (index == -1)
1484  {
1486  LOG_INFO("Cannot determine whether pier side simulation should be switched on or off.");
1487  IDSetSwitch(&SimulatePierSideSP, nullptr);
1488  return false;
1489  }
1490 
1491  bool pierSideEnabled = index == 0;
1492 
1493  LOGF_INFO("Simulating Pier Side %s.", (pierSideEnabled ? "enabled" : "disabled"));
1494 
1495  setSimulatePierSide(pierSideEnabled);
1496  if (pierSideEnabled)
1497  {
1498  // set the pier side from the current Ra
1499  // assumes we haven't tracked across the meridian
1501  }
1502  return true;
1503  }
1504 
1506  // Joystick Motion Control Mode
1508  if (!strcmp(name, MotionControlModeTP.name))
1509  {
1510  IUUpdateSwitch(&MotionControlModeTP, states, names, n);
1512  IDSetSwitch(&MotionControlModeTP, nullptr);
1514  LOG_INFO("Motion control is set to 4-way joystick.");
1516  LOG_INFO("Motion control is set to 2 separate axes.");
1517  else
1518  DEBUGF(Logger::DBG_WARNING, "Motion control is set to unknown value %d!", n);
1519  return true;
1520  }
1521 
1523  // Joystick Lock Axis
1525  if (!strcmp(name, LockAxisSP.name))
1526  {
1527  IUUpdateSwitch(&LockAxisSP, states, names, n);
1528  LockAxisSP.s = IPS_OK;
1529  IDSetSwitch(&LockAxisSP, nullptr);
1530  if (LockAxisS[AXIS_RA].s == ISS_ON)
1531  LOG_INFO("Joystick motion is locked to West/East axis only.");
1532  else if (LockAxisS[AXIS_DE].s == ISS_ON)
1533  LOG_INFO("Joystick motion is locked to North/South axis only.");
1534  else
1535  LOG_INFO("Joystick motion is unlocked.");
1536  return true;
1537  }
1538 
1540  // Scope Apply Config
1542  if (name && std::string(name) == "APPLY_SCOPE_CONFIG")
1543  {
1544  IUUpdateSwitch(&ScopeConfigsSP, states, names, n);
1545  bool rc = LoadScopeConfig();
1546  ScopeConfigsSP.s = (rc ? IPS_OK : IPS_ALERT);
1547  IDSetSwitch(&ScopeConfigsSP, nullptr);
1548  return true;
1549  }
1550  }
1551 
1552  bool rc = controller->ISNewSwitch(dev, name, states, names, n);
1553  if (rc)
1554  {
1555  ISwitchVectorProperty *useJoystick = getSwitch("USEJOYSTICK");
1556  if (useJoystick && useJoystick->sp[0].s == ISS_ON)
1557  {
1560  }
1561  else
1562  {
1565  }
1566 
1567  }
1568 
1569  // Nobody has claimed this, so, ignore it
1570  return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
1571 }
1572 
1574 {
1575  if (telescopeConnection > 0)
1576  {
1579  else if (getActiveConnection() == tcpConnection)
1581  }
1582 
1583  return Handshake();
1584 }
1585 
1586 bool Telescope::Handshake()
1587 {
1588  /* Test connection */
1590 }
1591 
1592 void Telescope::TimerHit()
1593 {
1594  if (isConnected())
1595  {
1596  bool rc;
1597 
1598  rc = ReadScopeStatus();
1599 
1600  if (!rc)
1601  {
1602  // read was not good
1603  EqNP.s = lastEqState = IPS_ALERT;
1604  IDSetNumber(&EqNP, nullptr);
1605  }
1606 
1608  }
1609 }
1610 
1611 bool Telescope::Goto(double ra, double dec)
1612 {
1613  INDI_UNUSED(ra);
1614  INDI_UNUSED(dec);
1615 
1616  DEBUG(Logger::DBG_WARNING, "GOTO is not supported.");
1617  return false;
1618 }
1619 
1620 bool Telescope::Abort()
1621 {
1622  DEBUG(Logger::DBG_WARNING, "Abort is not supported.");
1623  return false;
1624 }
1625 
1626 bool Telescope::Park()
1628  DEBUG(Logger::DBG_WARNING, "Parking is not supported.");
1629  return false;
1630 }
1631 
1632 bool Telescope::UnPark()
1633 {
1634  DEBUG(Logger::DBG_WARNING, "UnParking is not supported.");
1635  return false;
1637 
1638 bool Telescope::SetTrackMode(uint8_t mode)
1639 {
1640  INDI_UNUSED(mode);
1641  DEBUG(Logger::DBG_WARNING, "Tracking mode is not supported.");
1642  return false;
1643 }
1644 
1645 bool Telescope::SetTrackRate(double raRate, double deRate)
1646 {
1647  INDI_UNUSED(raRate);
1648  INDI_UNUSED(deRate);
1649  DEBUG(Logger::DBG_WARNING, "Custom tracking rates is not supported.");
1650  return false;
1651 }
1652 
1653 bool Telescope::SetTrackEnabled(bool enabled)
1655  INDI_UNUSED(enabled);
1656  DEBUG(Logger::DBG_WARNING, "Tracking state is not supported.");
1657  return false;
1658 }
1659 
1660 int Telescope::AddTrackMode(const char *name, const char *label, bool isDefault)
1662  TrackModeS = (TrackModeS == nullptr) ? static_cast<ISwitch *>(malloc(sizeof(ISwitch))) :
1663  static_cast<ISwitch *>(realloc(TrackModeS, (TrackModeSP.nsp + 1) * sizeof(ISwitch)));
1664 
1665  IUFillSwitch(&TrackModeS[TrackModeSP.nsp], name, label, isDefault ? ISS_ON : ISS_OFF);
1666 
1668  TrackModeSP.nsp++;
1670  return (TrackModeSP.nsp - 1);
1671 }
1672 
1674 {
1675  DEBUG(Logger::DBG_WARNING, "Parking is not supported.");
1676  return false;
1677 }
1678 
1680 {
1681  DEBUG(Logger::DBG_WARNING, "Parking is not supported.");
1682  return false;
1683 }
1684 
1685 bool Telescope::processTimeInfo(const char *utc, const char *offset)
1686 {
1687  struct ln_date utc_date;
1688  double utc_offset = 0;
1690  if (extractISOTime(utc, &utc_date) == -1)
1691  {
1692  TimeTP.s = IPS_ALERT;
1693  IDSetText(&TimeTP, "Date/Time is invalid: %s.", utc);
1694  return false;
1695  }
1696 
1697  utc_offset = atof(offset);
1698 
1699  if (updateTime(&utc_date, utc_offset))
1700  {
1701  IUSaveText(&TimeT[0], utc);
1702  IUSaveText(&TimeT[1], offset);
1703  TimeTP.s = IPS_OK;
1704  IDSetText(&TimeTP, nullptr);
1705  return true;
1706  }
1707  else
1708  {
1709  TimeTP.s = IPS_ALERT;
1710  IDSetText(&TimeTP, nullptr);
1711  return false;
1712  }
1713 }
1714 
1715 bool Telescope::processLocationInfo(double latitude, double longitude, double elevation)
1716 {
1717  // Do not update if not necessary
1718  // JM 2021-05-26: This can sometimes be problematic. Let child driver deals with duplicate requests.
1719 #if 0
1720  if (latitude == LocationN[LOCATION_LATITUDE].value && longitude == LocationN[LOCATION_LONGITUDE].value &&
1721  elevation == LocationN[LOCATION_ELEVATION].value)
1722  {
1723  LocationNP.s = IPS_OK;
1724  IDSetNumber(&LocationNP, nullptr);
1725  return true;
1726  }
1727  else
1728 #endif
1729  if (latitude == 0 && longitude == 0)
1730  {
1731  LOG_DEBUG("Silently ignoring invalid latitude and longitude.");
1732  LocationNP.s = IPS_IDLE;
1733  IDSetNumber(&LocationNP, nullptr);
1734  return false;
1735  }
1736 
1737  if (updateLocation(latitude, longitude, elevation))
1738  {
1739  LocationNP.s = IPS_OK;
1740  LocationN[LOCATION_LATITUDE].value = latitude;
1741  LocationN[LOCATION_LONGITUDE].value = longitude;
1742  LocationN[LOCATION_ELEVATION].value = elevation;
1743  // Update client display
1744  IDSetNumber(&LocationNP, nullptr);
1745 
1746  // Always save geographic coord config immediately.
1747  saveConfig(true, "GEOGRAPHIC_COORD");
1748 
1749  updateObserverLocation(latitude, longitude, elevation);
1750 
1751  return true;
1752  }
1753  else
1754  {
1756  // Update client display
1757  IDSetNumber(&LocationNP, nullptr);
1758 
1759  return false;
1760  }
1761 }
1762 
1763 bool Telescope::updateTime(ln_date *utc, double utc_offset)
1764 {
1765  INDI_UNUSED(utc);
1766  INDI_UNUSED(utc_offset);
1767  return true;
1768 }
1769 
1770 bool Telescope::updateLocation(double latitude, double longitude, double elevation)
1771 {
1772  INDI_UNUSED(latitude);
1773  INDI_UNUSED(longitude);
1774  INDI_UNUSED(elevation);
1775  return true;
1776 }
1777 
1778 void Telescope::updateObserverLocation(double latitude, double longitude, double elevation)
1780  m_Location.longitude = longitude;
1781  m_Location.latitude = latitude;
1782  m_Location.elevation = elevation;
1783  char lat_str[MAXINDIFORMAT] = {0}, lng_str[MAXINDIFORMAT] = {0};
1784 
1785  // Make display longitude to be in the standard 0 to +180 East, and 0 to -180 West.
1786  // No need to confuse new users with INDI format.
1787  double display_longitude = longitude > 180 ? longitude - 360 : longitude;
1788  fs_sexa(lat_str, m_Location.latitude, 2, 36000);
1789  fs_sexa(lng_str, display_longitude, 2, 36000);
1790  // Choose WGS 84, also known as EPSG:4326 for latitude/longitude ordering
1791  LOGF_INFO("Observer location updated: Latitude %.12s (%.2f) Longitude %.12s (%.2f)", lat_str, m_Location.latitude, lng_str,
1792  display_longitude);
1793 }
1795 bool Telescope::SetParkPosition(double Axis1Value, double Axis2Value)
1796 {
1797  INDI_UNUSED(Axis1Value);
1798  INDI_UNUSED(Axis2Value);
1799  return true;
1800 }
1801 
1802 void Telescope::SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
1803 {
1804  capability = cap;
1805  nSlewRate = slewRateCount;
1806 
1807  // If both GOTO and SYNC are supported
1808  if (CanGOTO() && CanSync())
1809  IUFillSwitchVector(&CoordSP, CoordS, 3, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
1810  ISR_1OFMANY, 60, IPS_IDLE);
1811  // If ONLY GOTO is supported
1812  else if (CanGOTO())
1813  IUFillSwitchVector(&CoordSP, CoordS, 2, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
1814  ISR_1OFMANY, 60, IPS_IDLE);
1815  // If ONLY SYNC is supported
1816  else if (CanSync())
1817  {
1818  IUFillSwitch(&CoordS[0], "SYNC", "Sync", ISS_ON);
1819  IUFillSwitchVector(&CoordSP, CoordS, 1, getDeviceName(), "ON_COORD_SET", "On Set", MAIN_CONTROL_TAB, IP_RW,
1820  ISR_1OFMANY, 60, IPS_IDLE);
1821  }
1822 
1823  if (nSlewRate >= 4)
1824  {
1825  free(SlewRateS);
1826  SlewRateS = static_cast<ISwitch *>(malloc(sizeof(ISwitch) * nSlewRate));
1827  //int step = nSlewRate / 4;
1828  for (int i = 0; i < nSlewRate; i++)
1829  {
1830  char name[4];
1831  snprintf(name, 4, "%dx", i + 1);
1833  }
1834 
1835  // strncpy((SlewRateS + (step * 0))->name, "SLEW_GUIDE", MAXINDINAME);
1836  // strncpy((SlewRateS + (step * 1))->name, "SLEW_CENTERING", MAXINDINAME);
1837  // strncpy((SlewRateS + (step * 2))->name, "SLEW_FIND", MAXINDINAME);
1838  // strncpy((SlewRateS + (nSlewRate - 1))->name, "SLEW_MAX", MAXINDINAME);
1839 
1840  // If number of slew rate is EXACTLY 4, then let's use common labels
1841  if (nSlewRate == 4)
1842  {
1843  strncpy((SlewRateS + (0))->label, "Guide", MAXINDILABEL);
1844  strncpy((SlewRateS + (1))->label, "Centering", MAXINDILABEL);
1845  strncpy((SlewRateS + (2))->label, "Find", MAXINDILABEL);
1846  strncpy((SlewRateS + (3))->label, "Max", MAXINDILABEL);
1847  }
1848 
1849  // By Default we set current Slew Rate to 0.5 of max
1850  (SlewRateS + (nSlewRate / 2))->s = ISS_ON;
1851 
1852  IUFillSwitchVector(&SlewRateSP, SlewRateS, nSlewRate, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate",
1854  }
1855 }
1856 
1857 void Telescope::SetParkDataType(TelescopeParkData type)
1858 {
1859  parkDataType = type;
1860 
1861  if (parkDataType != PARK_NONE)
1862  {
1863  switch (parkDataType)
1864  {
1865  case PARK_RA_DEC:
1866  IUFillNumber(&ParkPositionN[AXIS_RA], "PARK_RA", "RA (hh:mm:ss)", "%010.6m", 0, 24, 0, 0);
1867  IUFillNumber(&ParkPositionN[AXIS_DE], "PARK_DEC", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
1868  break;
1869 
1870  case PARK_HA_DEC:
1871  IUFillNumber(&ParkPositionN[AXIS_RA], "PARK_HA", "HA (hh:mm:ss)", "%010.6m", -12, 12, 0, 0);
1872  IUFillNumber(&ParkPositionN[AXIS_DE], "PARK_DEC", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
1873  break;
1874 
1875  case PARK_AZ_ALT:
1876  IUFillNumber(&ParkPositionN[AXIS_AZ], "PARK_AZ", "AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0);
1877  IUFillNumber(&ParkPositionN[AXIS_ALT], "PARK_ALT", "Alt D:M:S", "%10.6m", -90., 90.0, 0.0, 0);
1878  break;
1879 
1880  case PARK_RA_DEC_ENCODER:
1881  IUFillNumber(&ParkPositionN[AXIS_RA], "PARK_RA", "RA Encoder", "%.0f", 0, 16777215, 1, 0);
1882  IUFillNumber(&ParkPositionN[AXIS_DE], "PARK_DEC", "DEC Encoder", "%.0f", 0, 16777215, 1, 0);
1883  break;
1884 
1885  case PARK_AZ_ALT_ENCODER:
1886  IUFillNumber(&ParkPositionN[AXIS_RA], "PARK_AZ", "AZ Encoder", "%.0f", 0, 16777215, 1, 0);
1887  IUFillNumber(&ParkPositionN[AXIS_DE], "PARK_ALT", "ALT Encoder", "%.0f", 0, 16777215, 1, 0);
1888  break;
1889 
1890  default:
1891  break;
1892  }
1893 
1894  IUFillNumberVector(&ParkPositionNP, ParkPositionN, 2, getDeviceName(), "TELESCOPE_PARK_POSITION",
1895  "Park Position", SITE_TAB, IP_RW, 60, IPS_IDLE);
1896  }
1897 }
1898 
1899 void Telescope::SyncParkStatus(bool isparked)
1900 {
1901  IsParked = isparked;
1903  ParkSP.s = IPS_OK;
1904 
1905  if (IsParked)
1906  {
1907  ParkS[0].s = ISS_ON;
1909  LOG_INFO("Mount is parked.");
1910  }
1911  else
1912  {
1913  ParkS[1].s = ISS_ON;
1915  LOG_INFO("Mount is unparked.");
1916  }
1917 
1918  IDSetSwitch(&ParkSP, nullptr);
1919 }
1920 
1921 void Telescope::SetParked(bool isparked)
1922 {
1923  SyncParkStatus(isparked);
1924 
1925  if (parkDataType != PARK_NONE)
1926  WriteParkData();
1927 }
1928 
1929 bool Telescope::isParked()
1930 {
1931  return IsParked;
1932 }
1933 
1934 bool Telescope::InitPark()
1935 {
1936  const char *loadres = LoadParkData();
1937  if (loadres)
1938  {
1939  LOGF_INFO("InitPark: No Park data in file %s: %s", ParkDataFileName.c_str(), loadres);
1940  SyncParkStatus(false);
1941  return false;
1942  }
1943 
1946  LOGF_DEBUG("InitPark Axis1 %.2f Axis2 %.2f", Axis1ParkPosition, Axis2ParkPosition);
1947  ParkPositionN[AXIS_RA].value = Axis1ParkPosition;
1948  ParkPositionN[AXIS_DE].value = Axis2ParkPosition;
1949  IDSetNumber(&ParkPositionNP, nullptr);
1951  return true;
1952 }
1953 
1954 const char *Telescope::LoadParkXML()
1955 {
1956  wordexp_t wexp;
1957  FILE *fp = nullptr;
1958  LilXML *lp = nullptr;
1959  static char errmsg[512];
1960 
1961  XMLEle *parkxml = nullptr;
1962  XMLAtt *ap = nullptr;
1963  bool devicefound = false;
1964 
1965  ParkDeviceName = getDeviceName();
1966  ParkstatusXml = nullptr;
1967  ParkdeviceXml = nullptr;
1968  ParkpositionXml = nullptr;
1969  ParkpositionAxis1Xml = nullptr;
1970  ParkpositionAxis2Xml = nullptr;
1971 
1972  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
1973  {
1974  wordfree(&wexp);
1975  return "Badly formed filename.";
1976  }
1977 
1978  if (!(fp = fopen(wexp.we_wordv[0], "r")))
1979  {
1980  wordfree(&wexp);
1981  return strerror(errno);
1982  }
1983  wordfree(&wexp);
1984 
1985  lp = newLilXML();
1986 
1987  if (ParkdataXmlRoot)
1988  delXMLEle(ParkdataXmlRoot);
1989 
1990  ParkdataXmlRoot = readXMLFile(fp, lp, errmsg);
1991  fclose(fp);
1992 
1993  delLilXML(lp);
1994  if (!ParkdataXmlRoot)
1995  return errmsg;
1996 
1997  parkxml = nextXMLEle(ParkdataXmlRoot, 1);
1998 
1999  if (!parkxml)
2000  return "Empty park file.";
2001 
2002  if (!strcmp(tagXMLEle(parkxml), "parkdata"))
2003  {
2004  delXMLEle(parkxml);
2005  return "Not a park data file";
2006  }
2007 
2008  while (parkxml)
2009  {
2010  if (strcmp(tagXMLEle(parkxml), "device"))
2011  {
2012  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
2013  continue;
2014  }
2015  ap = findXMLAtt(parkxml, "name");
2016  if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName)))
2017  {
2018  devicefound = true;
2019  break;
2020  }
2021  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
2022  }
2023 
2024  if (!devicefound)
2025  {
2026  delXMLEle(parkxml);
2027  return "No park data found for this device";
2028  }
2029 
2030  ParkdeviceXml = parkxml;
2031  ParkstatusXml = findXMLEle(parkxml, "parkstatus");
2032  ParkpositionXml = findXMLEle(parkxml, "parkposition");
2033  ParkpositionAxis1Xml = findXMLEle(ParkpositionXml, "axis1position");
2034  ParkpositionAxis2Xml = findXMLEle(ParkpositionXml, "axis2position");
2035 
2036 
2037  if (ParkstatusXml == nullptr || ParkpositionAxis1Xml == nullptr || ParkpositionAxis2Xml == nullptr)
2038  {
2039  return "Park data invalid or missing.";
2040  }
2041 
2042  return nullptr;
2043 }
2044 
2045 const char *Telescope::LoadParkData()
2046 {
2047  IsParked = false;
2048 
2049  const char *result = LoadParkXML();
2050  if (result != nullptr)
2051  return result;
2052 
2053  if (!strcmp(pcdataXMLEle(ParkstatusXml), "true"))
2054  IsParked = true;
2055 
2056  double axis1Pos = std::numeric_limits<double>::quiet_NaN();
2057  double axis2Pos = std::numeric_limits<double>::quiet_NaN();
2058 
2059  int rc = sscanf(pcdataXMLEle(ParkpositionAxis1Xml), "%lf", &axis1Pos);
2060  if (rc != 1)
2061  {
2062  return "Unable to parse Park Position Axis 1.";
2063  }
2064  rc = sscanf(pcdataXMLEle(ParkpositionAxis2Xml), "%lf", &axis2Pos);
2065  if (rc != 1)
2066  {
2067  return "Unable to parse Park Position Axis 2.";
2068  }
2069 
2070  if (std::isnan(axis1Pos) == false && std::isnan(axis2Pos) == false)
2071  {
2072  Axis1ParkPosition = axis1Pos;
2073  Axis2ParkPosition = axis2Pos;
2074  return nullptr;
2075  }
2076 
2077  return "Failed to parse Park Position.";
2078 }
2079 
2081 {
2082  // We need to refresh parking data in case other devices parking states were updated since we
2083  // read the data the first time.
2084  if (LoadParkXML() != nullptr)
2085  LOG_DEBUG("Failed to refresh parking data.");
2086 
2087  wordexp_t wexp;
2088  FILE *fp = nullptr;
2089  LilXML *lp = nullptr;
2090  static char errmsg[512];
2091 
2092  XMLEle *parkxml = nullptr;
2093  XMLAtt *ap = nullptr;
2094  bool devicefound = false;
2095 
2096  ParkDeviceName = getDeviceName();
2097 
2098  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
2099  {
2100  wordfree(&wexp);
2101  return false;
2102  }
2103 
2104  if (!(fp = fopen(wexp.we_wordv[0], "r")))
2105  {
2106  wordfree(&wexp);
2107  LOGF_ERROR("Failed to purge park data: %s", strerror(errno));
2108  return false;
2109  }
2110  wordfree(&wexp);
2111 
2112  lp = newLilXML();
2113 
2114  if (ParkdataXmlRoot)
2115  delXMLEle(ParkdataXmlRoot);
2116 
2117  ParkdataXmlRoot = readXMLFile(fp, lp, errmsg);
2118  fclose(fp);
2119 
2120  delLilXML(lp);
2121  if (!ParkdataXmlRoot)
2122  return false;
2123 
2124  parkxml = nextXMLEle(ParkdataXmlRoot, 1);
2125 
2126  if (!parkxml)
2127  return false;
2128 
2129  if (!strcmp(tagXMLEle(parkxml), "parkdata"))
2130  {
2131  delXMLEle(parkxml);
2132  return false;
2133  }
2134 
2135  while (parkxml)
2136  {
2137  if (strcmp(tagXMLEle(parkxml), "device"))
2138  {
2139  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
2140  continue;
2141  }
2142  ap = findXMLAtt(parkxml, "name");
2143  if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName)))
2144  {
2145  devicefound = true;
2146  break;
2147  }
2148  parkxml = nextXMLEle(ParkdataXmlRoot, 0);
2149  }
2150 
2151  if (!devicefound)
2152  return false;
2153 
2154  delXMLEle(parkxml);
2155 
2156  ParkstatusXml = nullptr;
2157  ParkdeviceXml = nullptr;
2158  ParkpositionXml = nullptr;
2159  ParkpositionAxis1Xml = nullptr;
2160  ParkpositionAxis2Xml = nullptr;
2161 
2162  wordexp(ParkDataFileName.c_str(), &wexp, 0);
2163  if (!(fp = fopen(wexp.we_wordv[0], "w")))
2164  {
2165  wordfree(&wexp);
2166  LOGF_INFO("WriteParkData: can not write file %s: %s", ParkDataFileName.c_str(), strerror(errno));
2167  return false;
2168  }
2169  prXMLEle(fp, ParkdataXmlRoot, 0);
2170  fclose(fp);
2171  wordfree(&wexp);
2172 
2173  return true;
2174 }
2175 
2177 {
2178  // We need to refresh parking data in case other devices parking states were updated since we
2179  // read the data the first time.
2180  if (LoadParkXML() != nullptr)
2181  LOG_DEBUG("Failed to refresh parking data.");
2182 
2183  wordexp_t wexp;
2184  FILE *fp;
2185  char pcdata[30];
2186  ParkDeviceName = getDeviceName();
2187 
2188  if (wordexp(ParkDataFileName.c_str(), &wexp, 0))
2189  {
2190  wordfree(&wexp);
2191  LOGF_INFO("WriteParkData: can not write file %s: Badly formed filename.",
2192  ParkDataFileName.c_str());
2193  return false;
2194  }
2195 
2196  if (!(fp = fopen(wexp.we_wordv[0], "w")))
2197  {
2198  wordfree(&wexp);
2199  LOGF_INFO("WriteParkData: can not write file %s: %s", ParkDataFileName.c_str(),
2200  strerror(errno));
2201  return false;
2202  }
2203 
2204  if (!ParkdataXmlRoot)
2205  ParkdataXmlRoot = addXMLEle(nullptr, "parkdata");
2206 
2207  if (!ParkdeviceXml)
2208  {
2209  ParkdeviceXml = addXMLEle(ParkdataXmlRoot, "device");
2210  addXMLAtt(ParkdeviceXml, "name", ParkDeviceName);
2211  }
2212 
2213  if (!ParkstatusXml)
2214  ParkstatusXml = addXMLEle(ParkdeviceXml, "parkstatus");
2215  if (!ParkpositionXml)
2216  ParkpositionXml = addXMLEle(ParkdeviceXml, "parkposition");
2217  if (!ParkpositionAxis1Xml)
2218  ParkpositionAxis1Xml = addXMLEle(ParkpositionXml, "axis1position");
2219  if (!ParkpositionAxis2Xml)
2220  ParkpositionAxis2Xml = addXMLEle(ParkpositionXml, "axis2position");
2221 
2222  editXMLEle(ParkstatusXml, (IsParked ? "true" : "false"));
2223 
2224  snprintf(pcdata, sizeof(pcdata), "%lf", Axis1ParkPosition);
2225  editXMLEle(ParkpositionAxis1Xml, pcdata);
2226  snprintf(pcdata, sizeof(pcdata), "%lf", Axis2ParkPosition);
2227  editXMLEle(ParkpositionAxis2Xml, pcdata);
2228 
2229  prXMLEle(fp, ParkdataXmlRoot, 0);
2230  fclose(fp);
2231  wordfree(&wexp);
2232 
2233  return true;
2234 }
2235 
2236 double Telescope::GetAxis1Park() const
2237 {
2238  return Axis1ParkPosition;
2239 }
2240 double Telescope::GetAxis1ParkDefault() const
2241 {
2242  return Axis1DefaultParkPosition;
2243 }
2244 double Telescope::GetAxis2Park() const
2245 {
2246  return Axis2ParkPosition;
2247 }
2248 double Telescope::GetAxis2ParkDefault() const
2249 {
2250  return Axis2DefaultParkPosition;
2251 }
2253 void Telescope::SetAxis1Park(double value)
2254 {
2255  LOGF_DEBUG("Setting Park Axis1 to %.2f", value);
2256  Axis1ParkPosition = value;
2257  ParkPositionN[AXIS_RA].value = value;
2258  IDSetNumber(&ParkPositionNP, nullptr);
2259 }
2261 void Telescope::SetAxis1ParkDefault(double value)
2262 {
2263  LOGF_DEBUG("Setting Default Park Axis1 to %.2f", value);
2264  Axis1DefaultParkPosition = value;
2265 }
2266 
2267 void Telescope::SetAxis2Park(double value)
2268 {
2269  LOGF_DEBUG("Setting Park Axis2 to %.2f", value);
2270  Axis2ParkPosition = value;
2271  ParkPositionN[AXIS_DE].value = value;
2272  IDSetNumber(&ParkPositionNP, nullptr);
2273 }
2274 
2275 void Telescope::SetAxis2ParkDefault(double value)
2276 {
2277  LOGF_DEBUG("Setting Default Park Axis2 to %.2f", value);
2278  Axis2DefaultParkPosition = value;
2279 }
2280 
2281 bool Telescope::isLocked() const
2282 {
2283  return DomePolicyS[DOME_LOCKS].s == ISS_ON && IsLocked;
2284 }
2285 
2286 bool Telescope::SetSlewRate(int index)
2287 {
2288  INDI_UNUSED(index);
2289  return true;
2290 }
2292 void Telescope::processButton(const char *button_n, ISState state)
2293 {
2294  //ignore OFF
2295  if (state == ISS_OFF)
2296  return;
2298  if (!strcmp(button_n, "ABORTBUTTON"))
2299  {
2300  ISwitchVectorProperty *trackSW = getSwitch("TELESCOPE_TRACK_MODE");
2301  // Only abort if we have some sort of motion going on
2303  (trackSW && trackSW->s == IPS_BUSY))
2304  {
2305  // Invoke parent processing so that Telescope takes care of abort cross-check
2306  ISState states[1] = { ISS_ON };
2307  const char *names[1] = { AbortS[0].name };
2308  ISNewSwitch(getDeviceName(), AbortSP.name, states, const_cast<char **>(names), 1);
2309  }
2310  }
2311  else if (!strcmp(button_n, "PARKBUTTON"))
2312  {
2313  ISState states[2] = { ISS_ON, ISS_OFF };
2314  const char *names[2] = { ParkS[0].name, ParkS[1].name };
2315  ISNewSwitch(getDeviceName(), ParkSP.name, states, const_cast<char **>(names), 2);
2316  }
2317  else if (!strcmp(button_n, "UNPARKBUTTON"))
2318  {
2319  ISState states[2] = { ISS_OFF, ISS_ON };
2320  const char *names[2] = { ParkS[0].name, ParkS[1].name };
2321  ISNewSwitch(getDeviceName(), ParkSP.name, states, const_cast<char **>(names), 2);
2322  }
2323  else if (!strcmp(button_n, "SLEWPRESETUP"))
2324  {
2325  processSlewPresets(1, 270);
2326  }
2327  else if (!strcmp(button_n, "SLEWPRESETDOWN"))
2328  {
2329  processSlewPresets(1, 90);
2330  }
2331 }
2332 
2333 void Telescope::processJoystick(const char *joystick_n, double mag, double angle)
2334 {
2335  if (MotionControlModeTP.sp[MOTION_CONTROL_JOYSTICK].s == ISS_ON && !strcmp(joystick_n, "MOTIONDIR"))
2336  {
2338  {
2339  DEBUG(Logger::DBG_WARNING, "Can not slew while mount is parking/parked.");
2340  return;
2341  }
2342 
2343  processNSWE(mag, angle);
2344  }
2345  else if (!strcmp(joystick_n, "SLEWPRESET"))
2346  processSlewPresets(mag, angle);
2347 }
2348 
2349 void Telescope::processAxis(const char *axis_n, double value)
2350 {
2352  {
2353  if (!strcmp(axis_n, "MOTIONDIRNS") || !strcmp(axis_n, "MOTIONDIRWE"))
2354  {
2356  {
2357  LOG_WARN("Cannot slew while mount is parking/parked.");
2358  return;
2359  }
2360 
2361  if (!strcmp(axis_n, "MOTIONDIRNS"))
2362  {
2363  // South
2364  if (value > 0)
2365  {
2366  motionDirNSValue = -1;
2367  }
2368  // North
2369  else if (value < 0)
2370  {
2371  motionDirNSValue = 1;
2372  }
2373  else
2374  {
2375  motionDirNSValue = 0;
2376  }
2377  }
2378  else if (!strcmp(axis_n, "MOTIONDIRWE"))
2379  {
2380  // East
2381  if (value > 0)
2382  {
2383  motionDirWEValue = 1;
2384  }
2385  // West
2386  else if (value < 0)
2387  {
2388  motionDirWEValue = -1;
2389  }
2390  else
2391  {
2392  motionDirWEValue = 0;
2393  }
2394  }
2395 
2396  float x = motionDirWEValue * sqrt(1 - pow(motionDirNSValue, 2) / 2.0f);
2397  float y = motionDirNSValue * sqrt(1 - pow(motionDirWEValue, 2) / 2.0f);
2398  float angle = atan2(y, x) * (180.0 / 3.141592653589);
2399  float mag = sqrt(pow(y, 2) + pow(x, 2));
2400  while (angle < 0)
2401  {
2402  angle += 360;
2403  }
2404  if (mag == 0)
2405  {
2406  angle = 0;
2407  }
2408 
2409  processNSWE(mag, angle);
2410  }
2411  }
2412 }
2413 
2414 void Telescope::processNSWE(double mag, double angle)
2415 {
2416  if (mag < 0.5)
2417  {
2418  // Moving in the same direction will make it stop
2419  if (MovementNSSP.s == IPS_BUSY)
2420  {
2422  {
2425  IDSetSwitch(&MovementNSSP, nullptr);
2426  }
2427  else
2428  {
2431  }
2432  }
2433 
2434  if (MovementWESP.s == IPS_BUSY)
2435  {
2437  {
2440  IDSetSwitch(&MovementWESP, nullptr);
2441  }
2442  else
2443  {
2445  IDSetSwitch(&MovementWESP, nullptr);
2446  }
2447  }
2448  }
2449  // Put high threshold
2450  else if (mag > 0.9)
2451  {
2452  // Only one axis can move at a time
2453  if (LockAxisS[AXIS_RA].s == ISS_ON)
2454  {
2455  // West
2456  if (angle >= 90 && angle <= 270)
2457  angle = 180;
2458  // East
2459  else
2460  angle = 0;
2461  }
2462  else if (LockAxisS[AXIS_DE].s == ISS_ON)
2463  {
2464  // North
2465  if (angle >= 0 && angle <= 180)
2466  angle = 90;
2467  // South
2468  else
2469  angle = 270;
2470  }
2471 
2472  // Snap angle to x or y direction if close to corresponding axis (i.e. deviation < 15°)
2473  if (angle > 75 && angle < 105)
2474  {
2475  angle = 90;
2476  }
2477  if (angle > 165 && angle < 195)
2478  {
2479  angle = 180;
2480  }
2481  if (angle > 255 && angle < 285)
2482  {
2483  angle = 270;
2484  }
2485  if (angle > 345 || angle < 15)
2486  {
2487  angle = 0;
2488  }
2489 
2490  // North
2491  if (angle > 0 && angle < 180)
2492  {
2493  // Don't try to move if you're busy and moving in the same direction
2494  if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON)
2496 
2500  IDSetSwitch(&MovementNSSP, nullptr);
2501  }
2502  // South
2503  if (angle > 180 && angle < 360)
2504  {
2505  // Don't try to move if you're busy and moving in the same direction
2506  if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON)
2508 
2512  IDSetSwitch(&MovementNSSP, nullptr);
2513  }
2514  // East
2515  if (angle < 90 || angle > 270)
2516  {
2517  // Don't try to move if you're busy and moving in the same direction
2518  if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON)
2520 
2524  IDSetSwitch(&MovementWESP, nullptr);
2525  }
2526 
2527  // West
2528  if (angle > 90 && angle < 270)
2529  {
2530  // Don't try to move if you're busy and moving in the same direction
2531  if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON)
2533 
2537  IDSetSwitch(&MovementWESP, nullptr);
2538  }
2539  }
2540 }
2541 
2542 void Telescope::processSlewPresets(double mag, double angle)
2543 {
2544  // high threshold, only 1 is accepted
2545  if (mag != 1)
2546  return;
2547 
2548  int currentIndex = IUFindOnSwitchIndex(&SlewRateSP);
2549 
2550  // Up
2551  if (angle > 0 && angle < 180)
2552  {
2553  if (currentIndex <= 0)
2554  return;
2555 
2557  SlewRateS[currentIndex - 1].s = ISS_ON;
2558  SetSlewRate(currentIndex - 1);
2559  }
2560  // Down
2561  else
2562  {
2563  if (currentIndex >= SlewRateSP.nsp - 1)
2564  return;
2565 
2567  SlewRateS[currentIndex + 1].s = ISS_ON;
2568  SetSlewRate(currentIndex - 1);
2569  }
2570 
2571  IDSetSwitch(&SlewRateSP, nullptr);
2572 }
2573 
2574 void Telescope::joystickHelper(const char *joystick_n, double mag, double angle, void *context)
2575 {
2576  static_cast<Telescope *>(context)->processJoystick(joystick_n, mag, angle);
2577 }
2578 
2579 void Telescope::axisHelper(const char *axis_n, double value, void *context)
2580 {
2581  static_cast<Telescope *>(context)->processAxis(axis_n, value);
2582 }
2583 
2584 void Telescope::buttonHelper(const char *button_n, ISState state, void *context)
2585 {
2586  static_cast<Telescope *>(context)->processButton(button_n, state);
2587 }
2588 
2589 void Telescope::setPierSide(TelescopePierSide side)
2591  // ensure that the scope knows it's pier side or the pier side is simulated
2592  if (HasPierSide() == false && getSimulatePierSide() == false)
2593  return;
2594 
2596 
2598  {
2599  PierSideS[PIER_WEST].s = (side == PIER_WEST) ? ISS_ON : ISS_OFF;
2601  PierSideSP.s = IPS_OK;
2602  IDSetSwitch(&PierSideSP, nullptr);
2603 
2605  }
2606 }
2607 
2614 {
2615  // return unknown if the mount does not have pier side, this will be the case for a fork mount
2616  // where a pier flip is not required.
2617  if (!HasPierSide() && !HasPierSideSimulation())
2619 
2620  // calculate the hour angle and derive the pier side
2622  double hourAngle = get_local_hour_angle(lst, ra);
2623 
2624  return hourAngle <= 0 ? INDI::Telescope::PIER_WEST : INDI::Telescope::PIER_EAST;
2625 }
2626 
2627 void Telescope::setPECState(TelescopePECState state)
2628 {
2630 
2632  {
2633 
2634  PECStateS[PEC_OFF].s = (state == PEC_ON) ? ISS_OFF : ISS_ON;
2635  PECStateS[PEC_ON].s = (state == PEC_ON) ? ISS_ON : ISS_OFF;
2636  PECStateSP.s = IPS_OK;
2637  IDSetSwitch(&PECStateSP, nullptr);
2638 
2640  }
2641 }
2642 
2644 {
2645  if (!CheckFile(ScopeConfigFileName, false))
2646  {
2647  LOGF_INFO("Can't open XML file (%s) for read", ScopeConfigFileName.c_str());
2648  return false;
2649  }
2650  LilXML *XmlHandle = newLilXML();
2651  FILE *FilePtr = fopen(ScopeConfigFileName.c_str(), "r");
2652  XMLEle *RootXmlNode = nullptr;
2653  XMLEle *CurrentXmlNode = nullptr;
2654  XMLAtt *Ap = nullptr;
2655  bool DeviceFound = false;
2656  char ErrMsg[512];
2657 
2658  RootXmlNode = readXMLFile(FilePtr, XmlHandle, ErrMsg);
2659  fclose(FilePtr);
2660  delLilXML(XmlHandle);
2661  XmlHandle = nullptr;
2662  if (!RootXmlNode)
2663  {
2664  LOGF_INFO("Failed to parse XML file (%s): %s", ScopeConfigFileName.c_str(), ErrMsg);
2665  return false;
2666  }
2667  if (std::string(tagXMLEle(RootXmlNode)) != ScopeConfigRootXmlNode)
2668  {
2669  LOGF_INFO("Not a scope config XML file (%s)", ScopeConfigFileName.c_str());
2670  delXMLEle(RootXmlNode);
2671  return false;
2672  }
2673  CurrentXmlNode = nextXMLEle(RootXmlNode, 1);
2674  // Find the current telescope in the config file
2675  while (CurrentXmlNode)
2676  {
2677  if (std::string(tagXMLEle(CurrentXmlNode)) != ScopeConfigDeviceXmlNode)
2678  {
2679  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2680  continue;
2681  }
2682  Ap = findXMLAtt(CurrentXmlNode, ScopeConfigNameXmlNode.c_str());
2683  if (Ap && !strcmp(valuXMLAtt(Ap), getDeviceName()))
2684  {
2685  DeviceFound = true;
2686  break;
2687  }
2688  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2689  }
2690  if (!DeviceFound)
2691  {
2692  LOGF_INFO("No a scope config found for %s in the XML file (%s)", getDeviceName(),
2693  ScopeConfigFileName.c_str());
2694  delXMLEle(RootXmlNode);
2695  return false;
2696  }
2697  // Read the values
2698  XMLEle *XmlNode = nullptr;
2699  const int ConfigIndex = GetScopeConfigIndex();
2700  double ScopeFoc = 0, ScopeAp = 0;
2701  double GScopeFoc = 0, GScopeAp = 0;
2702  std::string ConfigName;
2703 
2704  CurrentXmlNode = findXMLEle(CurrentXmlNode, ("config" + std::to_string(ConfigIndex)).c_str());
2705  if (!CurrentXmlNode)
2706  {
2708  "Config %d is not found in the XML file (%s). To save a new config, update and set scope properties and "
2709  "config name.",
2710  ConfigIndex, ScopeConfigFileName.c_str());
2711  delXMLEle(RootXmlNode);
2712  return false;
2713  }
2714  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigScopeFocXmlNode.c_str());
2715  if (!XmlNode || sscanf(pcdataXMLEle(XmlNode), "%lf", &ScopeFoc) != 1)
2716  {
2717  LOGF_INFO("Can't read the telescope focal length from the XML file (%s)",
2718  ScopeConfigFileName.c_str());
2719  delXMLEle(RootXmlNode);
2720  return false;
2721  }
2722  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigScopeApXmlNode.c_str());
2723  if (!XmlNode || sscanf(pcdataXMLEle(XmlNode), "%lf", &ScopeAp) != 1)
2724  {
2725  LOGF_INFO("Can't read the telescope aperture from the XML file (%s)",
2726  ScopeConfigFileName.c_str());
2727  delXMLEle(RootXmlNode);
2728  return false;
2729  }
2730  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigGScopeFocXmlNode.c_str());
2731  if (!XmlNode || sscanf(pcdataXMLEle(XmlNode), "%lf", &GScopeFoc) != 1)
2732  {
2733  LOGF_INFO("Can't read the guide scope focal length from the XML file (%s)",
2734  ScopeConfigFileName.c_str());
2735  delXMLEle(RootXmlNode);
2736  return false;
2737  }
2738  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigGScopeApXmlNode.c_str());
2739  if (!XmlNode || sscanf(pcdataXMLEle(XmlNode), "%lf", &GScopeAp) != 1)
2740  {
2741  LOGF_INFO("Can't read the guide scope aperture from the XML file (%s)",
2742  ScopeConfigFileName.c_str());
2743  delXMLEle(RootXmlNode);
2744  return false;
2745  }
2746  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigLabelApXmlNode.c_str());
2747  if (!XmlNode)
2748  {
2749  LOGF_INFO("Can't read the telescope config name from the XML file (%s)",
2750  ScopeConfigFileName.c_str());
2751  delXMLEle(RootXmlNode);
2752  return false;
2753  }
2754  ConfigName = pcdataXMLEle(XmlNode);
2755  // Store the loaded values
2756  if (IUFindNumber(&ScopeParametersNP, "TELESCOPE_FOCAL_LENGTH"))
2757  {
2758  IUFindNumber(&ScopeParametersNP, "TELESCOPE_FOCAL_LENGTH")->value = ScopeFoc;
2759  }
2760  if (IUFindNumber(&ScopeParametersNP, "TELESCOPE_APERTURE"))
2761  {
2762  IUFindNumber(&ScopeParametersNP, "TELESCOPE_APERTURE")->value = ScopeAp;
2763  }
2764  if (IUFindNumber(&ScopeParametersNP, "GUIDER_FOCAL_LENGTH"))
2765  {
2766  IUFindNumber(&ScopeParametersNP, "GUIDER_FOCAL_LENGTH")->value = GScopeFoc;
2767  }
2768  if (IUFindNumber(&ScopeParametersNP, "GUIDER_APERTURE"))
2769  {
2770  IUFindNumber(&ScopeParametersNP, "GUIDER_APERTURE")->value = GScopeAp;
2771  }
2772  if (IUFindText(&ScopeConfigNameTP, "SCOPE_CONFIG_NAME"))
2773  {
2774  IUSaveText(IUFindText(&ScopeConfigNameTP, "SCOPE_CONFIG_NAME"), ConfigName.c_str());
2775  }
2777  IDSetNumber(&ScopeParametersNP, nullptr);
2779  IDSetText(&ScopeConfigNameTP, nullptr);
2780  delXMLEle(RootXmlNode);
2781  return true;
2782 }
2783 
2785 {
2786  if (!CheckFile(ScopeConfigFileName, false))
2787  {
2788  return false;
2789  }
2790  LilXML *XmlHandle = newLilXML();
2791  FILE *FilePtr = fopen(ScopeConfigFileName.c_str(), "r");
2792  XMLEle *RootXmlNode = nullptr;
2793  XMLEle *CurrentXmlNode = nullptr;
2794  XMLAtt *Ap = nullptr;
2795  bool DeviceFound = false;
2796  char ErrMsg[512];
2797 
2798  RootXmlNode = readXMLFile(FilePtr, XmlHandle, ErrMsg);
2799  fclose(FilePtr);
2800  delLilXML(XmlHandle);
2801  XmlHandle = nullptr;
2802  if (!RootXmlNode)
2803  {
2804  return false;
2805  }
2806  if (std::string(tagXMLEle(RootXmlNode)) != ScopeConfigRootXmlNode)
2807  {
2808  delXMLEle(RootXmlNode);
2809  return false;
2810  }
2811  CurrentXmlNode = nextXMLEle(RootXmlNode, 1);
2812  // Find the current telescope in the config file
2813  while (CurrentXmlNode)
2814  {
2815  if (std::string(tagXMLEle(CurrentXmlNode)) != ScopeConfigDeviceXmlNode)
2816  {
2817  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2818  continue;
2819  }
2820  Ap = findXMLAtt(CurrentXmlNode, ScopeConfigNameXmlNode.c_str());
2821  if (Ap && !strcmp(valuXMLAtt(Ap), getDeviceName()))
2822  {
2823  DeviceFound = true;
2824  break;
2825  }
2826  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2827  }
2828  if (!DeviceFound)
2829  {
2830  delXMLEle(RootXmlNode);
2831  return false;
2832  }
2833  // Check the existence of Config #1 node
2834  CurrentXmlNode = findXMLEle(CurrentXmlNode, "config1");
2835  if (!CurrentXmlNode)
2836  {
2837  delXMLEle(RootXmlNode);
2838  return false;
2839  }
2840  return true;
2841 }
2842 
2844 {
2845  // Get the config values from the UI
2846  const int ConfigIndex = GetScopeConfigIndex();
2847  double ScopeFoc = 0, ScopeAp = 0;
2848  double GScopeFoc = 0, GScopeAp = 0;
2849  std::string ConfigName;
2850 
2851  if (IUFindNumber(&ScopeParametersNP, "TELESCOPE_FOCAL_LENGTH"))
2852  {
2853  ScopeFoc = IUFindNumber(&ScopeParametersNP, "TELESCOPE_FOCAL_LENGTH")->value;
2854  }
2855  if (IUFindNumber(&ScopeParametersNP, "TELESCOPE_APERTURE"))
2856  {
2857  ScopeAp = IUFindNumber(&ScopeParametersNP, "TELESCOPE_APERTURE")->value;
2858  }
2859  if (IUFindNumber(&ScopeParametersNP, "GUIDER_FOCAL_LENGTH"))
2860  {
2861  GScopeFoc = IUFindNumber(&ScopeParametersNP, "GUIDER_FOCAL_LENGTH")->value;
2862  }
2863  if (IUFindNumber(&ScopeParametersNP, "GUIDER_APERTURE"))
2864  {
2865  GScopeAp = IUFindNumber(&ScopeParametersNP, "GUIDER_APERTURE")->value;
2866  }
2867  if (IUFindText(&ScopeConfigNameTP, "SCOPE_CONFIG_NAME") &&
2868  IUFindText(&ScopeConfigNameTP, "SCOPE_CONFIG_NAME")->text)
2869  {
2870  ConfigName = IUFindText(&ScopeConfigNameTP, "SCOPE_CONFIG_NAME")->text;
2871  }
2872  // Save the values to the actual XML file
2873  if (!CheckFile(ScopeConfigFileName, true))
2874  {
2875  LOGF_INFO("Can't open XML file (%s) for write", ScopeConfigFileName.c_str());
2876  return false;
2877  }
2878  // Open the existing XML file for write
2879  LilXML *XmlHandle = newLilXML();
2880  FILE *FilePtr = fopen(ScopeConfigFileName.c_str(), "r");
2881  XMLEle *RootXmlNode = nullptr;
2882  XMLAtt *Ap = nullptr;
2883  bool DeviceFound = false;
2884  char ErrMsg[512];
2885 
2886  RootXmlNode = readXMLFile(FilePtr, XmlHandle, ErrMsg);
2887  delLilXML(XmlHandle);
2888  XmlHandle = nullptr;
2889  fclose(FilePtr);
2890 
2891  XMLEle *CurrentXmlNode = nullptr;
2892  XMLEle *XmlNode = nullptr;
2893 
2894  if (!RootXmlNode || std::string(tagXMLEle(RootXmlNode)) != ScopeConfigRootXmlNode)
2895  {
2896  RootXmlNode = addXMLEle(nullptr, ScopeConfigRootXmlNode.c_str());
2897  }
2898  CurrentXmlNode = nextXMLEle(RootXmlNode, 1);
2899  // Find the current telescope in the config file
2900  while (CurrentXmlNode)
2901  {
2902  if (std::string(tagXMLEle(CurrentXmlNode)) != ScopeConfigDeviceXmlNode)
2903  {
2904  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2905  continue;
2906  }
2907  Ap = findXMLAtt(CurrentXmlNode, ScopeConfigNameXmlNode.c_str());
2908  if (Ap && !strcmp(valuXMLAtt(Ap), getDeviceName()))
2909  {
2910  DeviceFound = true;
2911  break;
2912  }
2913  CurrentXmlNode = nextXMLEle(RootXmlNode, 0);
2914  }
2915  if (!DeviceFound)
2916  {
2917  CurrentXmlNode = addXMLEle(RootXmlNode, ScopeConfigDeviceXmlNode.c_str());
2918  addXMLAtt(CurrentXmlNode, ScopeConfigNameXmlNode.c_str(), getDeviceName());
2919  }
2920  // Add or update the config node
2921  XmlNode = findXMLEle(CurrentXmlNode, ("config" + std::to_string(ConfigIndex)).c_str());
2922  if (!XmlNode)
2923  {
2924  CurrentXmlNode = addXMLEle(CurrentXmlNode, ("config" + std::to_string(ConfigIndex)).c_str());
2925  }
2926  else
2927  {
2928  CurrentXmlNode = XmlNode;
2929  }
2930  // Add or update the telescope focal length
2931  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigScopeFocXmlNode.c_str());
2932  if (!XmlNode)
2933  {
2934  XmlNode = addXMLEle(CurrentXmlNode, ScopeConfigScopeFocXmlNode.c_str());
2935  }
2936  editXMLEle(XmlNode, std::to_string(ScopeFoc).c_str());
2937  // Add or update the telescope focal aperture
2938  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigScopeApXmlNode.c_str());
2939  if (!XmlNode)
2940  {
2941  XmlNode = addXMLEle(CurrentXmlNode, ScopeConfigScopeApXmlNode.c_str());
2942  }
2943  editXMLEle(XmlNode, std::to_string(ScopeAp).c_str());
2944  // Add or update the guide scope focal length
2945  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigGScopeFocXmlNode.c_str());
2946  if (!XmlNode)
2947  {
2948  XmlNode = addXMLEle(CurrentXmlNode, ScopeConfigGScopeFocXmlNode.c_str());
2949  }
2950  editXMLEle(XmlNode, std::to_string(GScopeFoc).c_str());
2951  // Add or update the guide scope focal aperture
2952  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigGScopeApXmlNode.c_str());
2953  if (!XmlNode)
2954  {
2955  XmlNode = addXMLEle(CurrentXmlNode, ScopeConfigGScopeApXmlNode.c_str());
2956  }
2957  editXMLEle(XmlNode, std::to_string(GScopeAp).c_str());
2958  // Add or update the config name
2959  XmlNode = findXMLEle(CurrentXmlNode, ScopeConfigLabelApXmlNode.c_str());
2960  if (!XmlNode)
2961  {
2962  XmlNode = addXMLEle(CurrentXmlNode, ScopeConfigLabelApXmlNode.c_str());
2963  }
2964  editXMLEle(XmlNode, ConfigName.c_str());
2965  // Save the final content
2966  FilePtr = fopen(ScopeConfigFileName.c_str(), "w");
2967  prXMLEle(FilePtr, RootXmlNode, 0);
2968  fclose(FilePtr);
2969  delXMLEle(RootXmlNode);
2970  return true;
2971 }
2972 
2973 std::string Telescope::GetHomeDirectory() const
2974 {
2975  // Check first the HOME environmental variable
2976  const char *HomeDir = getenv("HOME");
2977 
2978  // ...otherwise get the home directory of the current user.
2979  if (!HomeDir)
2980  {
2981  HomeDir = getpwuid(getuid())->pw_dir;
2982  }
2983  return (HomeDir ? std::string(HomeDir) : "");
2984 }
2985 
2987 {
2988  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG1") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG1")->s == ISS_ON)
2989  {
2990  return 1;
2991  }
2992  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG2") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG2")->s == ISS_ON)
2993  {
2994  return 2;
2995  }
2996  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG3") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG3")->s == ISS_ON)
2997  {
2998  return 3;
2999  }
3000  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG4") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG4")->s == ISS_ON)
3001  {
3002  return 4;
3003  }
3004  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG5") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG5")->s == ISS_ON)
3005  {
3006  return 5;
3007  }
3008  if (IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG6") && IUFindSwitch(&ScopeConfigsSP, "SCOPE_CONFIG6")->s == ISS_ON)
3009  {
3010  return 6;
3011  }
3012  return 0;
3013 }
3014 
3015 bool Telescope::CheckFile(const std::string &file_name, bool writable) const
3016 {
3017  FILE *FilePtr = fopen(file_name.c_str(), (writable ? "a" : "r"));
3018 
3019  if (FilePtr)
3020  {
3021  fclose(FilePtr);
3022  return true;
3023  }
3024  return false;
3025 }
3026 
3028 {
3029  char ts[32] = {0};
3030 
3031  std::time_t t = std::time(nullptr);
3032  struct std::tm *utctimeinfo = std::gmtime(&t);
3033 
3034  strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", utctimeinfo);
3035  IUSaveText(&TimeT[0], ts);
3036 
3037  struct std::tm *localtimeinfo = std::localtime(&t);
3038  snprintf(ts, sizeof(ts), "%4.2f", (localtimeinfo->tm_gmtoff / 3600.0));
3039  IUSaveText(&TimeT[1], ts);
3040 
3041  TimeTP.s = IPS_OK;
3042 
3043  IDSetText(&TimeTP, nullptr);
3044 }
3045 
3046 bool Telescope::getSimulatePierSide() const
3047 {
3048  return m_simulatePierSide;
3049 }
3050 
3051 const char * Telescope::getPierSideStr(TelescopePierSide ps)
3052 {
3053  switch (ps)
3054  {
3055  case PIER_WEST:
3056  return "PIER_WEST";
3057  case PIER_EAST:
3058  return "PIER_EAST";
3059  default:
3060  return "PIER_UNKNOWN";
3061  }
3063 
3064 void Telescope::setSimulatePierSide(bool simulate)
3065 {
3067  SimulatePierSideS[0].s = simulate ? ISS_ON : ISS_OFF;
3068  SimulatePierSideS[1].s = simulate ? ISS_OFF : ISS_ON;
3070  IDSetSwitch(&SimulatePierSideSP, nullptr);
3071 
3072  if (simulate)
3073  {
3076  }
3077  else
3078  {
3079  capability &= static_cast<uint32_t>(~TELESCOPE_HAS_PIER_SIDE);
3081  }
3082 
3083  m_simulatePierSide = simulate;
3084 }
3085 
3086 }
INDI::Telescope::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: inditelescope.cpp:816
INDI::Telescope::joystickHelper
static void joystickHelper(const char *joystick_n, double mag, double angle, void *context)
Definition: inditelescope.cpp:2590
DIRECTION_NORTH
@ DIRECTION_NORTH
Definition: indibasetypes.h:45
DIRECTION_SOUTH
@ DIRECTION_SOUTH
Definition: indibasetypes.h:46
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::Telescope::Telescope
Telescope()
Definition: inditelescope.cpp:58
INDI::Telescope::SCOPE_IDLE
@ SCOPE_IDLE
Definition: inditelescope.h:75
INDI::Telescope::DomePolicyS
ISwitch DomePolicyS[2]
Definition: inditelescope.h:767
INDI::Telescope::Abort
virtual bool Abort()
Abort any telescope motion including tracking if possible.
Definition: inditelescope.cpp:1636
INDI::Telescope::last_ns_motion
int last_ns_motion
Definition: inditelescope.h:857
newLilXML
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.c:148
INDI::Telescope::ActiveDeviceT
IText ActiveDeviceT[2]
Definition: inditelescope.h:763
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
INDI::Telescope::SAT_PASS_WINDOW_START
@ SAT_PASS_WINDOW_START
Index for start of the window.
Definition: inditelescope.h:810
Connection::TCP::getPortFD
int getPortFD() const
Definition: connectiontcp.h:120
INDI::Telescope::SlewRateS
ISwitch * SlewRateS
Definition: inditelescope.h:750
INDI::Telescope::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: inditelescope.cpp:658
INDI::Telescope::UpdateScopeConfig
bool UpdateScopeConfig()
Save scope settings to XML files.
Definition: inditelescope.cpp:2859
INDI::Telescope::SCOPE_CONFIG4
@ SCOPE_CONFIG4
Definition: inditelescope.h:884
INDI::Telescope::WriteParkData
bool WriteParkData()
Definition: inditelescope.cpp:2192
INDI::Telescope::SAT_PASS_WINDOW_COUNT
@ SAT_PASS_WINDOW_COUNT
Number of indices.
Definition: inditelescope.h:812
IUGetConfigNumber
int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
IUGetConfigNumber Opens configuration file and reads single number property.
Definition: indidriver.c:1390
INDI::Telescope::updateLocation
virtual bool updateLocation(double latitude, double longitude, double elevation)
Update telescope location settings.
Definition: inditelescope.cpp:1786
INDI::Telescope::sendTimeFromSystem
void sendTimeFromSystem()
Definition: inditelescope.cpp:3043
INDI::Telescope::PIER_WEST
@ PIER_WEST
Definition: inditelescope.h:124
INDI::Telescope::LoadScopeConfig
bool LoadScopeConfig()
Load scope settings from XML files.
Definition: inditelescope.cpp:2659
INDI::Telescope::PierSideSP
ISwitchVectorProperty PierSideSP
Definition: inditelescope.h:784
INDI::Telescope::GetAxis1ParkDefault
double GetAxis1ParkDefault() const
Definition: inditelescope.cpp:2256
INDI::Telescope::initProperties
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: inditelescope.cpp:82
INDI::Telescope::LocationN
INumber LocationN[3]
Definition: inditelescope.h:719
INDI::Telescope::SCOPE_SLEWING
@ SCOPE_SLEWING
Definition: inditelescope.h:76
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
INDI::Telescope::SAT_TRACK
@ SAT_TRACK
Track signal.
Definition: inditelescope.h:826
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
INDI::Telescope::SCOPE_PARKING
@ SCOPE_PARKING
Definition: inditelescope.h:78
INDI::Telescope::currentPECState
TelescopePECState currentPECState
Definition: inditelescope.h:854
INDI::Telescope::CoordS
ISwitch CoordS[3]
Definition: inditelescope.h:715
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
MAXINDITSTAMP
#define MAXINDITSTAMP
Definition: indiapi.h:196
ISwitch
One switch descriptor.
get_local_hour_angle
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition: indicom.c:1543
INDI::Controller::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
Definition: indicontroller.cpp:302
INDI::Telescope::setPierSide
void setPierSide(TelescopePierSide side)
Definition: inditelescope.cpp:2605
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
pcdataXMLEle
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:575
indicom.h
Implementations for common driver routines.
MOTION_TAB
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
Definition: defaultdevice.cpp:36
connectiontcp.h
INDI::Telescope::Goto
virtual bool Goto(double ra, double dec)
Move the scope to the supplied RA and DEC coordinates.
Definition: inditelescope.cpp:1627
INDI::Telescope::CanAbort
bool CanAbort()
Definition: inditelescope.h:220
INDI::Telescope::PARK_WRITE_DATA
@ PARK_WRITE_DATA
Definition: inditelescope.h:736
INDI::Telescope::expectedPierSide
TelescopePierSide expectedPierSide(double ra)
Calculate the expected pier side for scopes that do not report this property themselves.
Definition: inditelescope.cpp:2629
INDI::Logger::DBG_WARNING
@ DBG_WARNING
Definition: indilogger.h:193
INDI::Telescope::TrackSatS
ISwitch TrackSatS[SAT_TRACK_COUNT]
Definition: inditelescope.h:835
INDI_DIR_NS
INDI_DIR_NS
Definition: indibasetypes.h:44
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
INDI::Telescope::PIER_UNKNOWN
@ PIER_UNKNOWN
Definition: inditelescope.h:123
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
INDI::Telescope::MovementNSSP
ISwitchVectorProperty MovementNSSP
Definition: inditelescope.h:742
INDI::Telescope::Handshake
virtual bool Handshake()
perform handshake with device to check communication
Definition: inditelescope.cpp:1602
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
INDI::Telescope::CanSync
bool CanSync()
Definition: inditelescope.h:212
INumber
One number descriptor.
INDI::Telescope::buttonHelper
static void buttonHelper(const char *button_n, ISState state, void *context)
Definition: inditelescope.cpp:2600
Connection::Serial
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
Definition: connectionserial.h:56
INDI::Telescope::NewRaDec
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
Definition: inditelescope.cpp:693
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::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
DIRECTION_EAST
@ DIRECTION_EAST
Definition: indibasetypes.h:52
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_DIR_WE
INDI_DIR_WE
Definition: indibasetypes.h:50
INDI::Telescope::GetHomeDirectory
std::string GetHomeDirectory() const
Validate a file name.
Definition: inditelescope.cpp:2989
INDI::Telescope::TrackModeS
ISwitch * TrackModeS
Definition: inditelescope.h:843
INDI::Telescope::PARK_AZ_ALT_ENCODER
@ PARK_AZ_ALT_ENCODER
Definition: inditelescope.h:113
INDI::Telescope::lastPECState
TelescopePECState lastPECState
Definition: inditelescope.h:854
INDI::Telescope::HasPECState
bool HasPECState()
Definition: inditelescope.h:282
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
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::Telescope::SetSlewRate
virtual bool SetSlewRate(int index)
SetSlewRate Set desired slew rate index.
Definition: inditelescope.cpp:2302
INDI::Telescope::ScopeConfigGScopeFocXmlNode
const std::string ScopeConfigGScopeFocXmlNode
Definition: inditelescope.h:874
INDI::Telescope::PARK_CURRENT
@ PARK_CURRENT
Definition: inditelescope.h:734
INDI::Telescope::LocationNP
INumberVectorProperty LocationNP
Definition: inditelescope.h:718
INDI::Telescope::GetAxis1Park
double GetAxis1Park() const
Definition: inditelescope.cpp:2252
INDI::Telescope::SetAxis2Park
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:2283
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::Telescope::SetAxis1ParkDefault
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
Definition: inditelescope.cpp:2277
SATELLITE_TAB
const char * SATELLITE_TAB
SATELLITE_TAB.
Definition: defaultdevice.cpp:44
INDI::Telescope::processNSWE
void processNSWE(double mag, double angle)
Definition: inditelescope.cpp:2430
INDI::Telescope::ScopeConfigGScopeApXmlNode
const std::string ScopeConfigGScopeApXmlNode
Definition: inditelescope.h:875
INDI::Telescope::PARK_RA_DEC_ENCODER
@ PARK_RA_DEC_ENCODER
Definition: inditelescope.h:112
INDI::Telescope::InitPark
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
Definition: inditelescope.cpp:1950
INDI::Telescope::ParkOptionS
ISwitch ParkOptionS[4]
Definition: inditelescope.h:730
INDI::Telescope::TLEtoTrackT
IText TLEtoTrackT[1]
Definition: inditelescope.h:803
INDI::Telescope::DomePolicySP
ISwitchVectorProperty DomePolicySP
Definition: inditelescope.h:766
INDI::Telescope::PEC_ON
@ PEC_ON
Definition: inditelescope.h:132
SITE_TAB
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
Definition: defaultdevice.cpp:38
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::Telescope::MovementWES
ISwitch MovementWES[2]
Definition: inditelescope.h:745
INDI::Telescope::HasLocation
bool HasLocation()
Definition: inditelescope.h:252
INDI::Telescope::axisHelper
static void axisHelper(const char *axis_n, double value, void *context)
Definition: inditelescope.cpp:2595
INDI::Telescope::GetAxis2ParkDefault
double GetAxis2ParkDefault() const
Definition: inditelescope.cpp:2264
INDI::Logger::DBG_SESSION
@ DBG_SESSION
Definition: indilogger.h:194
INDI::Telescope::ScopeConfigsSP
ISwitchVectorProperty ScopeConfigsSP
Definition: inditelescope.h:889
INDI::DefaultDevice::getDefaultName
virtual const char * getDefaultName()=0
INDI::Telescope::LockAxisS
ISwitch LockAxisS[2]
Definition: inditelescope.h:779
INDI::Telescope::setSimulatePierSide
void setSimulatePierSide(bool value)
Definition: inditelescope.cpp:3080
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
INDI::Telescope::EqNP
INumberVectorProperty EqNP
Definition: inditelescope.h:701
INDI::Telescope::m_Location
IGeographicCoordinates m_Location
Definition: inditelescope.h:648
INDI::IGeographicCoordinates::elevation
double elevation
Definition: libastro.h:68
INDI::DefaultDevice::addPollPeriodControl
void addPollPeriodControl()
Add Polling period control to the driver.
Definition: defaultdevice.cpp:659
INDI::BaseDevice::getSwitch
INDI::PropertyView< ISwitch > * getSwitch(const char *name) const
Definition: basedevice.cpp:109
IUUpdateText
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:259
INDI::Telescope::ScopeConfigScopeFocXmlNode
const std::string ScopeConfigScopeFocXmlNode
Definition: inditelescope.h:872
INDI::Telescope::processSlewPresets
void processSlewPresets(double mag, double angle)
Definition: inditelescope.cpp:2558
INDI::Telescope::ScopeConfigNameTP
ITextVectorProperty ScopeConfigNameTP
Definition: inditelescope.h:892
INDI::Telescope::updateObserverLocation
void updateObserverLocation(double latitude, double longitude, double elevation)
Update location settings of the observer.
Definition: inditelescope.cpp:1794
INDI::Telescope::tcpConnection
Connection::TCP * tcpConnection
Definition: inditelescope.h:866
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::Telescope::lastPierSide
TelescopePierSide lastPierSide
Definition: inditelescope.h:793
INDI::Telescope::PurgeParkData
bool PurgeParkData()
Definition: inditelescope.cpp:2096
INDI::Telescope::updateTime
virtual bool updateTime(ln_date *utc, double utc_offset)
Update telescope time, date, and UTC offset.
Definition: inditelescope.cpp:1779
INDI::Telescope::HasPierSide
bool HasPierSide()
Definition: inditelescope.h:260
INDI::Telescope::DOME_IGNORED
@ DOME_IGNORED
Definition: inditelescope.h:138
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::Telescope::DOME_LOCKS
@ DOME_LOCKS
Definition: inditelescope.h:139
INDI::DefaultDevice::initProperties
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
Definition: defaultdevice.cpp:917
INDI::Telescope::setTelescopeConnection
void setTelescopeConnection(const uint8_t &value)
setTelescopeConnection Set telescope connection mode. Child class should call this in the constructor...
Definition: inditelescope.cpp:645
INDI::Telescope::TrackRateN
INumber TrackRateN[2]
Definition: inditelescope.h:851
INDI::Telescope::HasTrackMode
bool HasTrackMode()
Definition: inditelescope.h:290
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
INDI::Telescope::TrackState
TelescopeStatus TrackState
Definition: inditelescope.h:693
INDI::Telescope::ScopeConfigScopeApXmlNode
const std::string ScopeConfigScopeApXmlNode
Definition: inditelescope.h:873
INDI::Telescope::TargetN
INumber TargetN[2]
Definition: inditelescope.h:707
INDI::Telescope::isParked
bool isParked()
isParked is mount currently parked?
Definition: inditelescope.cpp:1945
INDI::Telescope::TimeTP
ITextVectorProperty TimeTP
Definition: inditelescope.h:758
INDI::Telescope::processAxis
void processAxis(const char *axis_n, double value)
Definition: inditelescope.cpp:2365
INDI::Telescope::AbortSP
ISwitchVectorProperty AbortSP
Definition: inditelescope.h:710
INDI::Telescope::getTelescopeConnection
uint8_t getTelescopeConnection() const
Definition: inditelescope.cpp:640
INDI::Telescope::TRACK_OFF
@ TRACK_OFF
Definition: inditelescope.h:103
Telescope
Class to provide general functionality of a telescope device.
IUFindOnSwitch
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *sp)
Returns the first ON switch it finds in the vector switch property.
Definition: indicom.c:1414
INDI::Telescope::SatPassWindowT
IText SatPassWindowT[SAT_PASS_WINDOW_COUNT]
Definition: inditelescope.h:819
INDI::Telescope::TRACK_ON
@ TRACK_ON
Definition: inditelescope.h:102
INDI::Telescope::last_we_motion
int last_we_motion
Definition: inditelescope.h:857
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
IUFindText
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indicom.c:1362
INDI::Telescope::processJoystick
void processJoystick(const char *joystick_n, double mag, double angle)
Definition: inditelescope.cpp:2349
INDI::Controller::CONTROLLER_AXIS
@ CONTROLLER_AXIS
Definition: indicontroller.h:84
INDI::Telescope::LOCATION_ELEVATION
@ LOCATION_ELEVATION
Definition: inditelescope.h:119
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
INDI::Telescope::ScopeConfigNameXmlNode
const std::string ScopeConfigNameXmlNode
Definition: inditelescope.h:871
type
__le16 type
Definition: pwc-ioctl.h:2
INDI::Telescope::HasPierSideSimulation
bool HasPierSideSimulation()
Definition: inditelescope.h:268
INDI::Telescope::SyncParkStatus
virtual void SyncParkStatus(bool isparked)
SyncParkStatus Update the state and switches for parking.
Definition: inditelescope.cpp:1915
INDI::Telescope::MotionControlModeT
ISwitch MotionControlModeT[2]
Definition: inditelescope.h:771
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::Telescope::MOTION_CONTROL_JOYSTICK
@ MOTION_CONTROL_JOYSTICK
Definition: inditelescope.h:774
delLilXML
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.c:157
INDI::IGeographicCoordinates::longitude
double longitude
Definition: libastro.h:66
INDI::Telescope::callHandshake
bool callHandshake()
callHandshake Helper function that sets the port file descriptor before calling the actual Handshake ...
Definition: inditelescope.cpp:1589
INDI::Telescope::ParkS
ISwitch ParkS[2]
Definition: inditelescope.h:723
INDI::Telescope::PARK_PURGE_DATA
@ PARK_PURGE_DATA
Definition: inditelescope.h:737
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::Telescope::SimulatePierSideS
ISwitch SimulatePierSideS[2]
Definition: inditelescope.h:788
INDI::Telescope::ScopeConfigNameT
IText ScopeConfigNameT[1]
Definition: inditelescope.h:893
_ISwitchVectorProperty::nsp
int nsp
Definition: indiapi.h:386
INDI::Telescope::TelescopePierSide
TelescopePierSide
Definition: inditelescope.h:121
INDI::Controller::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Definition: indicontroller.cpp:158
INDI::Telescope::ParkPositionN
INumber ParkPositionN[2]
Definition: inditelescope.h:726
INDI::IGeographicCoordinates::latitude
double latitude
Definition: libastro.h:67
INDI::Telescope::PARK_RA_DEC
@ PARK_RA_DEC
Definition: inditelescope.h:109
INDI::Telescope::HasTime
bool HasTime()
Definition: inditelescope.h:244
INDI::Telescope::ScopeConfigFileName
const std::string ScopeConfigFileName
The telescope/guide scope configuration file name.
Definition: inditelescope.h:896
INDI::Telescope::TLEtoTrackTP
ITextVectorProperty TLEtoTrackTP
Text Vector property defining the orbital elements of an artificial satellite (TLE)....
Definition: inditelescope.h:802
INDI::Controller::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root)
Definition: indicontroller.cpp:239
INDI::Telescope::CONNECTION_NONE
@ CONNECTION_NONE
Definition: inditelescope.h:148
INDI::Telescope::ScopeConfigDeviceXmlNode
const std::string ScopeConfigDeviceXmlNode
Definition: inditelescope.h:870
INDI::Controller::ISGetProperties
virtual void ISGetProperties(const char *dev)
Definition: indicontroller.cpp:123
INDI::Telescope::TrackModeSP
ISwitchVectorProperty TrackModeSP
Definition: inditelescope.h:842
INDI::Telescope::CONNECTION_TCP
@ CONNECTION_TCP
Definition: inditelescope.h:150
INDI::Telescope::ActiveDeviceTP
ITextVectorProperty ActiveDeviceTP
Definition: inditelescope.h:762
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::Telescope::SetTelescopeCapability
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount=0)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
Definition: inditelescope.cpp:1818
INDI::Controller::CONTROLLER_JOYSTICK
@ CONTROLLER_JOYSTICK
Definition: indicontroller.h:84
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
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::Telescope::MOTION_CONTROL_AXES
@ MOTION_CONTROL_AXES
Definition: inditelescope.h:775
inditelescope.h
INDI::Telescope::MOTION_START
@ MOTION_START
Definition: inditelescope.h:83
INDI::Telescope::TrackRateNP
INumberVectorProperty TrackRateNP
Definition: inditelescope.h:850
INDI::Telescope::TargetNP
INumberVectorProperty TargetNP
Definition: inditelescope.h:706
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
INDI::Telescope::CanPark
bool CanPark()
Definition: inditelescope.h:228
dec
double dec
Definition: ieqprolegacydriver.cpp:44
INDI::Telescope::SAT_TRACK_COUNT
@ SAT_TRACK_COUNT
State counter.
Definition: inditelescope.h:828
readXMLFile
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.c:622
INDI::Telescope::MovementWESP
ISwitchVectorProperty MovementWESP
Definition: inditelescope.h:746
extractISOTime
int extractISOTime(const char *timestr, struct ln_date *iso_date)
Extract ISO 8601 time and store it in a tm struct.
INDI::Telescope::SCOPE_CONFIG3
@ SCOPE_CONFIG3
Definition: inditelescope.h:883
tagXMLEle
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:569
xml_ele_
Definition: lilxml.c:105
INDI::Telescope::processButton
void processButton(const char *button_n, ISState state)
Definition: inditelescope.cpp:2308
INDI::Telescope::TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_PIER_SIDE
Definition: inditelescope.h:165
INDI::Telescope::PARK_HA_DEC
@ PARK_HA_DEC
Definition: inditelescope.h:110
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
AXIS_ALT
@ AXIS_ALT
Definition: indibasetypes.h:40
INDI::Telescope::SAT_HALT
@ SAT_HALT
Halt signal (abort)
Definition: inditelescope.h:827
INDI::Telescope::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: inditelescope.cpp:770
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
INDI::Telescope::ReadScopeStatus
virtual bool ReadScopeStatus()=0
Read telescope status.
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::Telescope::SetAxis1Park
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:2269
INDI::Telescope::SCOPE_CONFIG5
@ SCOPE_CONFIG5
Definition: inditelescope.h:885
INDI::Telescope::ParkOptionSP
ISwitchVectorProperty ParkOptionSP
Definition: inditelescope.h:731
INDI::Telescope::AbortS
ISwitch AbortS[1]
Definition: inditelescope.h:711
INDI::Telescope::UnPark
virtual bool UnPark()
Unpark the telescope if already parked.
Definition: inditelescope.cpp:1648
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
INDI::Telescope::currentPierSide
TelescopePierSide currentPierSide
Definition: inditelescope.h:793
INDI::Telescope::PARK_NONE
@ PARK_NONE
Definition: inditelescope.h:108
INDI::Telescope::~Telescope
virtual ~Telescope()
Definition: inditelescope.cpp:74
IUFindNumber
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1372
INDI::Telescope::SCOPE_TRACKING
@ SCOPE_TRACKING
Definition: inditelescope.h:77
MAXINDIFORMAT
#define MAXINDIFORMAT
Definition: indiapi.h:194
INDI::Telescope::ScopeParametersNP
INumberVectorProperty ScopeParametersNP
Definition: inditelescope.h:754
INDI::Telescope::MoveWE
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command)
Move the telescope in the direction dir.
Definition: inditelescope.cpp:756
INDI::Telescope::MotionControlModeTP
ISwitchVectorProperty MotionControlModeTP
Definition: inditelescope.h:770
INDI::Telescope::SCOPE_CONFIG1
@ SCOPE_CONFIG1
Definition: inditelescope.h:881
INDI::Telescope::LOCATION_LATITUDE
@ LOCATION_LATITUDE
Definition: inditelescope.h:117
LOG_DEBUG
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
INDI::Telescope::TrackStateSP
ISwitchVectorProperty TrackStateSP
Definition: inditelescope.h:846
INDI::Telescope::SetDefaultPark
virtual bool SetDefaultPark()
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: inditelescope.cpp:1695
INDI::Telescope::SCOPE_PARKED
@ SCOPE_PARKED
Definition: inditelescope.h:79
INDI::Telescope::CanControlTrack
bool CanControlTrack()
Definition: inditelescope.h:236
get_local_sidereal_time
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
INDI::Telescope::PECStateSP
ISwitchVectorProperty PECStateSP
Definition: inditelescope.h:839
INDI::Telescope::LoadParkData
const char * LoadParkData()
Definition: inditelescope.cpp:2061
INDI::Telescope::MovementNSS
ISwitch MovementNSS[2]
Definition: inditelescope.h:741
INDI::Telescope::SetCurrentPark
virtual bool SetCurrentPark()
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: inditelescope.cpp:1689
INDI::Telescope::capability
uint32_t capability
Definition: inditelescope.h:856
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
INDI::Telescope::serialConnection
Connection::Serial * serialConnection
Definition: inditelescope.h:865
indicontroller.h
INDI::Telescope::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: inditelescope.cpp:320
INDI::Telescope::SCOPE_CONFIG6
@ SCOPE_CONFIG6
Definition: inditelescope.h:886
INDI::Telescope::EqN
INumber EqN[2]
Definition: inditelescope.h:702
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::Telescope::ScopeParametersN
INumber ScopeParametersN[4]
Definition: inditelescope.h:753
INDI::Telescope::SetParkDataType
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
Definition: inditelescope.cpp:1873
INDI::Controller::CONTROLLER_BUTTON
@ CONTROLLER_BUTTON
Definition: indicontroller.h:84
INDI::Telescope::SetAxis2ParkDefault
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
Definition: inditelescope.cpp:2291
INDI::Telescope::MoveNS
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command)
Start or Stop the telescope motion in the direction dir.
Definition: inditelescope.cpp:745
INDI::Telescope::LockAxisSP
ISwitchVectorProperty LockAxisSP
Definition: inditelescope.h:780
INDI::Telescope::ScopeConfigRootXmlNode
const std::string ScopeConfigRootXmlNode
Definition: inditelescope.h:869
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
INDI::Telescope::CanTrackSatellite
bool CanTrackSatellite()
Definition: inditelescope.h:275
INDI::Telescope::TimeT
IText TimeT[2]
Definition: inditelescope.h:757
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::Telescope::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: inditelescope.cpp:536
INDI::Telescope::SetParked
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Definition: inditelescope.cpp:1937
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::Telescope::PierSideS
ISwitch PierSideS[2]
Definition: inditelescope.h:783
INDI::Telescope::parkDataType
TelescopeParkData parkDataType
Definition: inditelescope.h:899
INDI::Telescope::IsParked
bool IsParked
Definition: inditelescope.h:898
INDI::Telescope::CoordSP
ISwitchVectorProperty CoordSP
Definition: inditelescope.h:714
INDI::Telescope::SetTrackEnabled
virtual bool SetTrackEnabled(bool enabled)
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
Definition: inditelescope.cpp:1669
valuXMLAtt
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:593
INDI::Telescope::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: inditelescope.cpp:1029
findXMLEle
XMLEle * findXMLEle(XMLEle *ep, const char *tag)
Find an XML element within an XML element.
Definition: lilxml.c:506
AXIS_AZ
@ AXIS_AZ
Definition: indibasetypes.h:39
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
INDI::DefaultDevice::saveConfig
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
Definition: defaultdevice.cpp:221
INDI::Telescope::setPECState
void setPECState(TelescopePECState state)
Definition: inditelescope.cpp:2643
INDI::Telescope::SlewRateSP
ISwitchVectorProperty SlewRateSP
Definition: inditelescope.h:749
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
prXMLEle
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.c:699
INDI::Telescope::GetScopeConfigIndex
int GetScopeConfigIndex() const
Get the scope config index.
Definition: inditelescope.cpp:3002
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
DIRECTION_WEST
@ DIRECTION_WEST
Definition: indibasetypes.h:51
INDI::Telescope::ScopeConfigs
ISwitch ScopeConfigs[6]
Definition: inditelescope.h:888
INDI::Telescope::LOCATION_LONGITUDE
@ LOCATION_LONGITUDE
Definition: inditelescope.h:118
TRACKRATE_SIDEREAL
#define TRACKRATE_SIDEREAL
Definition: indicom.h:54
DEBUGF
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
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
IUFindIndex
int IUFindIndex(const char *needle, char **hay, unsigned int n)
Returns the index of the string in a string array.
Definition: indidriver.c:1861
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
INDI::Telescope::MOTION_STOP
@ MOTION_STOP
Definition: inditelescope.h:84
MAXINDILABEL
#define MAXINDILABEL
Definition: indiapi.h:191
INDI::Telescope::SetTrackMode
virtual bool SetTrackMode(uint8_t mode)
SetTrackMode Set active tracking mode. Do not change track state.
Definition: inditelescope.cpp:1654
INDI::Telescope::CanGOTO
bool CanGOTO()
Definition: inditelescope.h:204
LilXML_
Definition: lilxml.c:91
INDI::Telescope::PECStateS
ISwitch PECStateS[2]
Definition: inditelescope.h:838
INDI::Telescope::Park
virtual bool Park()
Park the telescope to its home position.
Definition: inditelescope.cpp:1642
INDI::Telescope::RememberTrackState
TelescopeStatus RememberTrackState
RememberTrackState Remember last state of Track State to fall back to in case of errors or aborts.
Definition: inditelescope.h:698
INDI::Telescope::AddTrackMode
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
Definition: inditelescope.cpp:1676
INDI::Telescope::ParkPositionNP
INumberVectorProperty ParkPositionNP
Definition: inditelescope.h:727
INDI::Telescope::HasDefaultScopeConfig
bool HasDefaultScopeConfig()
Load scope settings from XML files.
Definition: inditelescope.cpp:2800
INDI::Telescope::SCOPE_CONFIG2
@ SCOPE_CONFIG2
Definition: inditelescope.h:882
INDI::Telescope::HasTrackRate
bool HasTrackRate()
Definition: inditelescope.h:298
INDI::Telescope::SetParkPosition
virtual bool SetParkPosition(double Axis1Value, double Axis2Value)
SetParkPosition Set desired parking position to the supplied value. This ONLY sets the desired park p...
Definition: inditelescope.cpp:1811
INDI::Controller::initProperties
virtual bool initProperties()
Definition: indicontroller.cpp:109
ISState
ISState
Switch state.
Definition: indiapi.h:148
Connection::Serial::getPortFD
int getPortFD() const
Definition: connectionserial.h:136
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
INDI::Telescope::PARK_DEFAULT
@ PARK_DEFAULT
Definition: inditelescope.h:735
INDI::Telescope::isLocked
bool isLocked() const
isLocked is mount currently locked?
Definition: inditelescope.cpp:2297
INDI::Telescope::getPierSideStr
const char * getPierSideStr(TelescopePierSide ps)
Definition: inditelescope.cpp:3067
INDI::Telescope::Sync
virtual bool Sync(double ra, double dec)
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition: inditelescope.cpp:736
INDI::Telescope::PortFD
int PortFD
Definition: inditelescope.h:864
IUFindSwitch
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indicom.c:1382
INDI::Telescope::PARK_AZ_ALT
@ PARK_AZ_ALT
Definition: inditelescope.h:111
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::Telescope::TimerHit
virtual void TimerHit() override
Called when setTimer() time is up.
Definition: inditelescope.cpp:1608
_ISwitchVectorProperty::sp
ISwitch * sp
Definition: indiapi.h:384
INDI::Telescope::PEC_OFF
@ PEC_OFF
Definition: inditelescope.h:131
INDI::Telescope::SAT_PASS_WINDOW_END
@ SAT_PASS_WINDOW_END
Index for end of the window.
Definition: inditelescope.h:811
INDI::Telescope::updateProperties
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: inditelescope.cpp:356
INDI::Telescope::GetAxis2Park
double GetAxis2Park() const
Definition: inditelescope.cpp:2260
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1465
INDI::Telescope::TrackSatSP
ISwitchVectorProperty TrackSatSP
Switch Vector property defining the state of the satellite tracking of the mount. Example implementat...
Definition: inditelescope.h:834
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
INDI::Telescope::ParkSP
ISwitchVectorProperty ParkSP
Definition: inditelescope.h:722
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::Telescope::ScopeConfigLabelApXmlNode
const std::string ScopeConfigLabelApXmlNode
Definition: inditelescope.h:876
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.
errno
int errno
INDI::Telescope::PIER_EAST
@ PIER_EAST
Definition: inditelescope.h:125
INDI::Telescope::TrackStateS
ISwitch TrackStateS[2]
Definition: inditelescope.h:847
INDI::Telescope::CONNECTION_SERIAL
@ CONNECTION_SERIAL
Definition: inditelescope.h:149
INDI::Telescope::CheckFile
bool CheckFile(const std::string &file_name, bool writable) const
Check if a file exists and it is readable.
Definition: inditelescope.cpp:3031
INDI::Controller::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Definition: indicontroller.cpp:183
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
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
AXIS_DE
@ AXIS_DE
Definition: indibasetypes.h:34
findXMLAtt
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:493
INDI::Telescope::SatPassWindowTP
ITextVectorProperty SatPassWindowTP
Text Vector property defining the start and end of a satellite pass (window contains pass)....
Definition: inditelescope.h:818
INDI::Telescope::getSimulatePierSide
bool getSimulatePierSide() const
Definition: inditelescope.cpp:3062
_ISwitchVectorProperty
Switch vector property descriptor.
Definition: indiapi.h:365
INDI::Telescope::SimulatePierSideSP
ISwitchVectorProperty SimulatePierSideSP
Definition: inditelescope.h:787
INDI::Telescope::SetTrackRate
virtual bool SetTrackRate(double raRate, double deRate)
SetTrackRate Set custom tracking rates.
Definition: inditelescope.cpp:1661
INDI::DefaultDevice::getActiveConnection
Connection::Interface * getActiveConnection()
Definition: defaultdevice.cpp:1245
INDI::BaseDevice::TELESCOPE_INTERFACE
@ TELESCOPE_INTERFACE
Definition: basedevice.h:72
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151