Instrument Neutral Distributed Interface INDI  2.0.2
telescope_simulator.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2015 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 "telescope_simulator.h"
20 #include "scopesim_helper.h"
21 
22 #include "indicom.h"
23 
24 #include <cmath>
25 #include <cstring>
26 #include <memory>
27 
28 // We declare an auto pointer to ScopeSim.
29 static std::unique_ptr<ScopeSim> telescope_sim(new ScopeSim());
30 
31 #define RA_AXIS 0
32 #define DEC_AXIS 1
33 #define GUIDE_NORTH 0
34 #define GUIDE_SOUTH 1
35 #define GUIDE_WEST 0
36 #define GUIDE_EAST 1
37 
39 {
40  DBG_SCOPE = static_cast<uint32_t>(INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"));
41 
45  4);
46 
47  /* initialize random seed: */
48  srand(static_cast<uint32_t>(time(nullptr)));
49 
50  // initalise axis positions, for GEM pointing at pole, counterweight down
51  axisPrimary.setDegrees(90.0);
52  axisPrimary.TrackRate(Axis::SIDEREAL);
53  axisSecondary.setDegrees(90.0);
54 }
55 
57 {
58  return "Telescope Simulator";
59 }
60 
62 {
63  /* Make sure to init parent properties first */
65 
66 #ifdef USE_SIM_TAB
67  // mount type and alignment properties, these are in the Simulation tab
68  IUFillSwitch(&mountTypeS[Alignment::ALTAZ], "ALTAZ", "AltAz", ISS_OFF);
69  IUFillSwitch(&mountTypeS[Alignment::EQ_FORK], "EQ_FORK", "Fork (Eq)", ISS_OFF);
70  IUFillSwitch(&mountTypeS[Alignment::EQ_GEM], "EQ_GEM", "GEM", ISS_ON);
71  IUFillSwitchVector(&mountTypeSP, mountTypeS, 3, getDeviceName(), "MOUNT_TYPE", "Mount Type",
72  "Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE );
73 
74  IUFillSwitch(&simPierSideS[0], "PS_OFF", "Off", ISS_OFF);
75  IUFillSwitch(&simPierSideS[1], "PS_ON", "On", ISS_ON);
76  IUFillSwitchVector(&simPierSideSP, simPierSideS, 2, getDeviceName(), "SIM_PIER_SIDE", "Sim Pier Side",
77  "Simulation", IP_WO, ISR_1OFMANY, 60, IPS_IDLE );
78 
79  IUFillNumber(&mountModelN[0], "MM_IH", "Ha Zero (IH)", "%g", -5, 5, 0.01, 0);
80  IUFillNumber(&mountModelN[1], "MM_ID", "Dec Zero (ID)", "%g", -5, 5, 0.01, 0);
81  IUFillNumber(&mountModelN[2], "MM_CH", "Cone (CH)", "%g", -5, 5, 0.01, 0);
82  IUFillNumber(&mountModelN[3], "MM_NP", "Ha/Dec (NP)", "%g", -5, 5, 0.01, 0);
83  IUFillNumber(&mountModelN[4], "MM_MA", "Pole Azm (MA)", "%g", -5, 5, 0.01, 0);
84  IUFillNumber(&mountModelN[5], "MM_ME", "Pole elev (ME)", "%g", -5, 5, 0.01, 0);
85  IUFillNumberVector(&mountModelNP, mountModelN, 6, getDeviceName(), "MOUNT_MODEL", "Mount Model",
86  "Simulation", IP_WO, 0, IPS_IDLE);
87 
88  IUFillNumber(&flipHourAngleN[0], "FLIP_HA", "Hour Angle (deg)", "%g", -20, 20, 0.1, 0);
89  IUFillNumberVector(&flipHourAngleNP, flipHourAngleN, 1, getDeviceName(), "FLIP_HA", "Flip Posn.",
90  "Simulation", IP_WO, 0, IPS_IDLE);
91 
92  IUFillNumber(&mountAxisN[0], "PRIMARY", "Primary (Ha)", "%g", -180, 180, 0.01, 0);
93  IUFillNumber(&mountAxisN[1], "SECONDARY", "Secondary (Dec)", "%g", -180, 180, 0.01, 0);
94  IUFillNumberVector(&mountAxisNP, mountAxisN, 2, getDeviceName(), "MOUNT_AXES", "Mount Axes",
95  "Simulation", IP_RO, 0, IPS_IDLE);
96 #endif
97 
98  /* How fast do we guide compared to sidereal rate */
99  IUFillNumber(&GuideRateN[RA_AXIS], "GUIDE_RATE_WE", "W/E Rate", "%g", 0, 1, 0.1, 0.5);
100  IUFillNumber(&GuideRateN[DEC_AXIS], "GUIDE_RATE_NS", "N/S Rate", "%g", 0, 1, 0.1, 0.5);
101  IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0,
102  IPS_IDLE);
103 
104  IUFillSwitch(&SlewRateS[SLEW_GUIDE], "SLEW_GUIDE", "Guide", ISS_OFF);
105  IUFillSwitch(&SlewRateS[SLEW_CENTERING], "SLEW_CENTERING", "Centering", ISS_OFF);
106  IUFillSwitch(&SlewRateS[SLEW_FIND], "SLEW_FIND", "Find", ISS_OFF);
107  IUFillSwitch(&SlewRateS[SLEW_MAX], "SLEW_MAX", "Max", ISS_ON);
108  IUFillSwitchVector(&SlewRateSP, SlewRateS, 4, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB,
109  IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
110 
111  // Add Tracking Modes, the order must match the order of the TelescopeTrackMode enum
112  AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
113  AddTrackMode("TRACK_SOLAR", "Solar");
114  AddTrackMode("TRACK_LUNAR", "Lunar");
115  AddTrackMode("TRACK_CUSTOM", "Custom");
116 
117  // Let's simulate it to be an F/7.5 120mm telescope
118  ScopeParametersN[0].value = 120;
119  ScopeParametersN[1].value = 900;
120  ScopeParametersN[2].value = 120;
121  ScopeParametersN[3].value = 900;
122 
123  // RA is a rotating frame, while HA or Alt/Az is not
125 
127 
128  /* Add debug controls so we may debug driver if necessary */
129  addDebugControl();
130 
132 
134 
135  return true;
136 }
137 
138 void ScopeSim::ISGetProperties(const char *dev)
139 {
140  /* First we let our parent populate */
142 
143 #ifdef USE_SIM_TAB
144  defineProperty(&mountTypeSP);
145  loadConfig(true, mountTypeSP.name);
146  defineProperty(&simPierSideSP);
147  loadConfig(true, simPierSideSP.name);
148  defineProperty(&mountModelNP);
149  loadConfig(true, mountModelNP.name);
150  defineProperty(&mountAxisNP);
151  defineProperty(&flipHourAngleNP);
152  loadConfig(true, flipHourAngleNP.name);
153 #endif
154  /*
155  if (isConnected())
156  {
157  defineProperty(&GuideNSNP);
158  defineProperty(&GuideWENP);
159  defineProperty(&GuideRateNP);
160  defineProperty(&EqPENV);
161  defineProperty(&PEErrNSSP);
162  defineProperty(&PEErrWESP);
163  }
164  */
165 }
166 
168 {
169  updateMountAndPierSide();
170 
172 
173  if (isConnected())
174  {
177  defineProperty(&GuideRateNP);
178  loadConfig(true, GuideRateNP.name);
179 
180  if (InitPark())
181  {
182 
183  if (isParked())
184  {
185  // at this point there is a valid ParkData.xml available
186 
187  alignment.latitude = Angle(LocationN[LOCATION_LATITUDE].value);
188  alignment.longitude = Angle(LocationN[LOCATION_LONGITUDE].value);
189  currentRA = (alignment.lst() - Angle(ParkPositionN[AXIS_RA].value, Angle::ANGLE_UNITS::HOURS)).Hours();
190  currentDEC = ParkPositionN[AXIS_DE].value;
191  Sync(currentRA, currentDEC);
192 
193  }
194  // If loading parking data is successful, we just set the default parking values.
195  SetAxis1ParkDefault(-6.);
197  }
198  else
199  {
200  // Otherwise, we set all parking data to default in case no parking data is found.
201  SetAxis1Park(-6.);
202  SetAxis2Park(0.);
203  SetAxis1ParkDefault(-6.);
205  }
206 
208  }
209  else
210  {
213  deleteProperty(GuideRateNP.name);
214  }
215 
216  return true;
217 }
218 
220 {
221  LOG_INFO("Telescope simulator is online.");
223 
224  return true;
225 }
226 
228 {
229  LOG_INFO("Telescope simulator is offline.");
230  return true;
231 }
232 
234 {
235  // new axis control
236  axisPrimary.update();
237  axisSecondary.update();
238 
239  Angle ra, dec;
240  alignment.mountToApparentRaDec(axisPrimary.position, axisSecondary.position, &ra, &dec);
241 
242  // move both axes
243  currentRA = ra.Hours();
244  currentDEC = dec.Degrees();
245 
246  // update properties from the axis
247  if (alignment.mountType == Alignment::MOUNT_TYPE::EQ_GEM)
248  {
249  setPierSide(fabs(axisSecondary.position.Degrees()) > 90 ? PIER_WEST : PIER_EAST);
250  }
251 
252  bool slewing = axisPrimary.isSlewing || axisSecondary.isSlewing;
253  switch (TrackState)
254  {
255  case SCOPE_PARKING:
256  if (!slewing)
257  {
258  SetParked(true);
259  EqNP.s = IPS_IDLE;
260  LOG_INFO("Telescope slew is complete. Parked");
261  }
262  break;
263  case SCOPE_SLEWING:
264  if (!slewing)
265  {
266  // It seems to be required that tracking is enabled when a slew finishes but is it correct?
267  // if the mount was not tracking before the slew should it remain not tracking?
269  SetTrackEnabled(true);
270  EqNP.s = IPS_IDLE;
271  LOG_INFO("Telescope slew is complete. Tracking...");
272 
273  // check the slew accuracy
274  auto dRa = targetRA - currentRA;
275  auto dDec = targetDEC - currentDEC;
276  LOGF_DEBUG("slew accuracy %f, %f", dRa * 15 * 3600, dDec * 3600);
277  }
278  break;
279  default:
280  break;
281  }
282 
283  if (guidingEW && !axisPrimary.IsGuiding())
284  {
285  GuideWENP.np[0].value = 0;
286  GuideWENP.np[1].value = 0;
288  guidingEW = false;
289  }
290 
291  if (guidingNS && !axisSecondary.IsGuiding())
292  {
293  GuideNSNP.np[0].value = 0;
294  GuideNSNP.np[1].value = 0;
296  guidingNS = false;
297  }
298 
299 #ifdef USE_SIM_TAB
300  double axisRA = axisPrimary.position.Degrees();
301  double axisDE = axisSecondary.position.Degrees();
302  // No need to spam log until we have some actual changes.
303  if (std::fabs(mountAxisN[AXIS_RA].value - axisRA) > 0.0001 ||
304  std::fabs(mountAxisN[AXIS_DE].value - axisDE) > 0.0001)
305  {
306  mountAxisN[AXIS_RA].value = axisRA;
307  mountAxisN[AXIS_DE].value = axisDE;
308 
309  LOGF_EXTRA1("%s: %f, ra %f", axisPrimary.axisName, axisPrimary.position.Degrees(), ra.Hours());
310  LOGF_EXTRA1("%s: %f, dec %f", axisSecondary.axisName, axisSecondary.position.Degrees(), dec.Degrees());
311 
312  IDSetNumber(&mountAxisNP, nullptr);
313  }
314 #endif
315 
316  char RAStr[64], DecStr[64];
317  fs_sexa(RAStr, currentRA, 2, 3600);
318  fs_sexa(DecStr, currentDEC, 2, 3600);
319  DEBUGF(DBG_SCOPE, "Current RA: %s Current DEC: %s", RAStr, DecStr);
320 
321  NewRaDec(currentRA, currentDEC);
322 
323  return true;
324 }
325 
326 bool ScopeSim::Goto(double r, double d)
327 {
328  StartSlew(r, d, SCOPE_SLEWING);
329  return true;
330 }
331 
332 bool ScopeSim::Sync(double ra, double dec)
333 {
334  Angle a1, a2;
335  // set the mount axes to the position that will cause it to report the sync position
336  alignment.apparentRaDecToMount(Angle(ra * 15.0), Angle(dec), &a1, &a2);
337  axisPrimary.setDegrees(a1.Degrees());
338  axisSecondary.setDegrees(a2.Degrees());
339 
340  Angle r, d;
341  alignment.mountToApparentRaDec(a1, a2, &r, &d);
342  LOGF_DEBUG("sync to %f, %f, reached %f, %f", ra, dec, r.Hours(), d.Degrees());
343  currentRA = r.Hours();
344  currentDEC = d.Degrees();
345 
346  LOG_INFO("Sync is successful.");
347 
348  EqNP.s = IPS_OK;
349 
350  NewRaDec(currentRA, currentDEC);
351 
352  return true;
353 }
354 
356 {
357  double ra = (alignment.lst() - Angle(GetAxis1Park() * 15.)).Degrees() / 15.;
358  StartSlew(ra, GetAxis2Park(), SCOPE_PARKING);
359  return true;
360 }
361 
362 // common code for GoTo and park
363 void ScopeSim::StartSlew(double ra, double dec, TelescopeStatus status)
364 {
365  Angle primary, secondary;
366  alignment.apparentRaDecToMount(Angle(ra * 15.0), Angle(dec), &primary, &secondary);
367 
368  axisPrimary.StartSlew(primary);
369  axisSecondary.StartSlew(secondary);
370 
371  targetRA = ra;
372  targetDEC = dec;
373  char RAStr[64], DecStr[64];
374 
375  fs_sexa(RAStr, targetRA, 2, 3600);
376  fs_sexa(DecStr, targetDEC, 2, 3600);
377 
378  const char * statusStr;
379  switch (status)
380  {
381  case SCOPE_PARKING:
382  statusStr = "Parking";
383  break;
384  case SCOPE_SLEWING:
385  statusStr = "Slewing";
386  break;
387  default:
388  statusStr = "unknown";
389  }
390  TrackState = status;
391 
392  LOGF_INFO("%s to RA: %s - DEC: %s", statusStr, RAStr, DecStr);
393 }
394 
396 {
397  SetParked(false);
398  return true;
399 }
400 
401 bool ScopeSim::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
402 {
403  // first check if it's for our device
404 
405  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
406  {
407  if (strcmp(name, "GUIDE_RATE") == 0)
408  {
409  IUUpdateNumber(&GuideRateNP, values, names, n);
410  GuideRateNP.s = IPS_OK;
411  IDSetNumber(&GuideRateNP, nullptr);
412  return true;
413  }
414 
415  if (strcmp(name, GuideNSNP.name) == 0 || strcmp(name, GuideWENP.name) == 0)
416  {
417  processGuiderProperties(name, values, names, n);
418  return true;
419  }
420 
421 #ifdef USE_SIM_TAB
422  if (strcmp(name, mountModelNP.name) == 0)
423  {
424  IUUpdateNumber(&mountModelNP, values, names, n);
425  mountModelNP.s = IPS_OK;
426  IDSetNumber(&mountModelNP, nullptr);
427  alignment.setCorrections(mountModelN[0].value, mountModelN[1].value,
428  mountModelN[2].value, mountModelN[3].value,
429  mountModelN[4].value, mountModelN[5].value);
430 
431  saveConfig(true, mountModelNP.name);
432  return true;
433  }
434 
435  if (strcmp(name, flipHourAngleNP.name) == 0)
436  {
437  IUUpdateNumber(&flipHourAngleNP, values, names, n);
438  flipHourAngleNP.s = IPS_OK;
439  IDSetNumber(&flipHourAngleNP, nullptr);
440  alignment.setFlipHourAngle(flipHourAngleN[0].value);
441  return true;
442  }
443 #endif
444  }
445 
446  // if we didn't process it, continue up the chain, let somebody else
447  // give it a shot
448  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
449 }
450 
451 bool ScopeSim::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
452 {
453  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
454  {
455 #ifdef USE_SIM_TAB
456  if (strcmp(name, mountTypeSP.name) == 0)
457  {
458  if (IUUpdateSwitch(&mountTypeSP, states, names, n) < 0)
459  return false;
460 
461  mountTypeSP.s = IPS_OK;
462  IDSetSwitch(&mountTypeSP, nullptr);
463  updateMountAndPierSide();
464  return true;
465  }
466  if (strcmp(name, simPierSideSP.name) == 0)
467  {
468  if (IUUpdateSwitch(&simPierSideSP, states, names, n) < 0)
469  return false;
470 
471  simPierSideSP.s = IPS_OK;
472  IDSetSwitch(&simPierSideSP, nullptr);
473  updateMountAndPierSide();
474  return true;
475  }
476 #endif
477  // Slew mode
478  if (strcmp(name, SlewRateSP.name) == 0)
479  {
480  if (IUUpdateSwitch(&SlewRateSP, states, names, n) < 0)
481  return false;
482 
483  SlewRateSP.s = IPS_OK;
484  IDSetSwitch(&SlewRateSP, nullptr);
485  return true;
486  }
487  }
488 
489  // Nobody has claimed this, so, ignore it
490  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
491 }
492 
494 {
495  axisPrimary.Abort();
496  axisSecondary.Abort();
497  return true;
498 }
499 
501 {
502  if (TrackState == SCOPE_PARKED)
503  {
504  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
505  return false;
506  }
507  mcRate = static_cast<int>(IUFindOnSwitchIndex(&SlewRateSP)) + 1;
508 
509  int rate = (dir == INDI_DIR_NS::DIRECTION_NORTH) ? mcRate : -mcRate;
510  LOGF_DEBUG("MoveNS dir %s, motion %s, rate %d", dir == DIRECTION_NORTH ? "N" : "S", command == 0 ? "start" : "stop", rate);
511 
512  axisSecondary.mcRate = command == MOTION_START ? rate : 0;
513 
514  return true;
515 }
516 
518 {
519  if (TrackState == SCOPE_PARKED)
520  {
521  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
522  return false;
523  }
524 
525  mcRate = static_cast<int>(IUFindOnSwitchIndex(&SlewRateSP)) + 1;
526  int rate = (dir == INDI_DIR_WE::DIRECTION_EAST) ? -mcRate : mcRate;
527  LOGF_DEBUG("MoveWE dir %d, motion %s, rate %d", dir == DIRECTION_EAST ? "E" : "W", command == 0 ? "start" : "stop", rate);
528 
529  axisPrimary.mcRate = command == MOTION_START ? rate : 0;
530  return true;
531 }
532 
534 {
535  double rate = GuideRateN[DEC_AXIS].value;
536  axisSecondary.StartGuide(rate, ms);
537  guidingNS = true;
538  return IPS_BUSY;
539 }
540 
542 {
543  double rate = GuideRateN[DEC_AXIS].value;
544  axisSecondary.StartGuide(-rate, ms);
545  guidingNS = true;
546  return IPS_BUSY;
547 }
548 
550 {
551  double rate = GuideRateN[RA_AXIS].value;
552  axisPrimary.StartGuide(-rate, ms);
553  guidingEW = true;
554  return IPS_BUSY;
555 }
556 
558 {
559  double rate = GuideRateN[RA_AXIS].value;
560  axisPrimary.StartGuide(rate, ms);
561  guidingEW = true;
562  return IPS_BUSY;
563 }
564 
566 {
567 
568  double ha = (alignment.lst() - Angle(currentRA, Angle::ANGLE_UNITS::HOURS)).Hours();
569  SetAxis1Park(ha);
570  SetAxis2Park(currentDEC);
571 
572  return true;
573 }
574 
576 {
577  // mount points to East (couter weights down) at the horizon
578  // works for both hemispheres
579  SetAxis1Park(-6.);
580  SetAxis2Park(0.);
581 
582  return true;
583 }
584 
585 bool ScopeSim::SetTrackMode(uint8_t mode)
586 {
587  switch (static_cast<TelescopeTrackMode>(mode))
588  {
589  case TRACK_SIDEREAL:
590  axisPrimary.TrackRate(Axis::SIDEREAL);
591  axisSecondary.TrackRate(Axis::OFF);
592  return true;
593  case TRACK_SOLAR:
594  axisPrimary.TrackRate(Axis::SOLAR);
595  axisSecondary.TrackRate(Axis::OFF);
596  return true;
597  case TRACK_LUNAR:
598  axisPrimary.TrackRate(Axis::LUNAR);
599  axisSecondary.TrackRate(Axis::OFF);
600  return true;
601  case TRACK_CUSTOM:
603  return true;
604  }
605  return false;
606 }
607 
608 bool ScopeSim::SetTrackEnabled(bool enabled)
609 {
610  axisPrimary.Tracking(enabled);
611  axisSecondary.Tracking(enabled);
612  return true;
613 }
614 
615 bool ScopeSim::SetTrackRate(double raRate, double deRate)
616 {
617  axisPrimary.TrackingRateDegSec = Angle(raRate / 3600.0);
618  axisSecondary.TrackingRateDegSec = Angle(deRate / 3600.0);
619  return true;
620 }
621 
623 {
625 
626 #ifdef USE_SIM_TAB
627  IUSaveConfigNumber(fp, &GuideRateNP);
628  IUSaveConfigSwitch(fp, &mountTypeSP);
629  IUSaveConfigSwitch(fp, &simPierSideSP);
630  IUSaveConfigNumber(fp, &mountModelNP);
631  IUSaveConfigNumber(fp, &flipHourAngleNP);
632 #endif
633  return true;
634 }
635 
636 bool ScopeSim::updateLocation(double latitude, double longitude, double elevation)
637 {
638  LOGF_DEBUG("Update location %8.3f, %8.3f, %4.0f", latitude, longitude, elevation);
639 
640  alignment.latitude = Angle(latitude);
641  alignment.longitude = Angle(longitude);
642 
643  INDI_UNUSED(elevation);
644  return true;
645 }
646 
647 bool ScopeSim::updateMountAndPierSide()
648 {
649 #ifdef USE_SIM_TAB
650  int mountType = IUFindOnSwitchIndex(&mountTypeSP);
651  int pierSide = IUFindOnSwitchIndex(&simPierSideSP);
652  if (mountType < 0 || pierSide < 0)
653  return false;
654 
655  // If nothing changed, return
656  if (mountType == m_MountType && pierSide == m_PierSide)
657  return true;
658 
659  m_MountType = mountType;
660  m_PierSide = pierSide;
661 
662  LOGF_INFO("update mount and pier side: Pier Side %s, mount type %d", pierSide == 0 ? "Off" : "On", mountType);
663 #else
664  int mountType = 2;
665  int pierSide = 1;
666 #endif
667  if ( mountType == Alignment::MOUNT_TYPE::ALTAZ)
668  {
669  LOG_INFO("AltAz mount type not implemented yet");
670  return false;
671  }
672 
673  alignment.mountType = static_cast<Alignment::MOUNT_TYPE>(mountType);
674  // update the pier side capability depending on the mount type
675  uint32_t cap = GetTelescopeCapability();
676  if (pierSide == 1 && mountType == 2)
677  {
679  }
680  else
681  {
682  cap &= ~static_cast<uint32_t>(TELESCOPE_HAS_PIER_SIDE);
683  }
684  SetTelescopeCapability(cap, 4);
685 
686  return true;
687 }
688 
690 
void setCorrections(double ih, double id, double ch, double np, double ma, double me)
setCorrections set the values of the six corrections
void apparentRaDecToMount(Angle apparentRa, Angle apparentDec, Angle *primary, Angle *secondary)
void mountToApparentRaDec(Angle primary, Angle secondary, Angle *apparentRa, Angle *apparentDec)
mountToApparentRaDec: convert mount position to apparent Ra, Dec
void setFlipHourAngle(double deg)
MOUNT_TYPE mountType
The Angle class This class implements an angle type. This holds an angle that is always in the range ...
double Hours()
Hours.
double Degrees()
Degrees.
Angle TrackingRateDegSec
TrackingRateDegSec.
bool isSlewing
const char * axisName
void setDegrees(double degrees)
void StartGuide(double rate, uint32_t durationMs)
StartGuide start guiding.
void Abort()
void Tracking(bool enabled)
void StartSlew(Angle angle)
void update()
Angle position
bool IsGuiding()
int mcRate
void TrackRate(AXIS_TRACK_RATE rate)
TrackRate set the track rate to one of the standard rates.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
uint16_t getDriverInterface() const
void addDebugControl()
Add Debug control to the driver.
virtual void GuideComplete(INDI_EQ_AXIS axis)
Call GuideComplete once the guiding pulse is complete.
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
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...
double GetAxis2Park() const
bool isParked()
isParked is mount currently parked?
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
ISwitchVectorProperty SlewRateSP
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
INumber ScopeParametersN[4]
INumber TrackRateN[2]
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
INumber LocationN[3]
void setPierSide(TelescopePierSide side)
ISwitch * SlewRateS
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
INumber ParkPositionN[2]
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
The ScopeSim class provides a simple mount simulator of an equatorial mount.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual const char * getDefaultName() override
virtual bool Disconnect() override
Disconnect from device.
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
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...
virtual bool Park() override
Park the telescope to its home position.
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
double ra
double dec
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
@ IP_WO
Definition: indiapi.h:185
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ AXIS_DE
Definition: indibasetypes.h:36
@ AXIS_RA
Definition: indibasetypes.h:35
INDI_DIR_WE
Definition: indibasetypes.h:55
@ DIRECTION_EAST
Definition: indibasetypes.h:57
INDI_DIR_NS
Definition: indibasetypes.h:48
@ DIRECTION_NORTH
Definition: indibasetypes.h:49
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
Definition: indicom.c:141
Implementations for common driver routines.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define LOGF_EXTRA1(fmt,...)
Definition: indilogger.h:84
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
std::unique_ptr< ScopeSim > telescope_sim(new ScopeSim())
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
Definition: indilogger.cpp:339
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
Definition: indilogger.cpp:72
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
#define RA_AXIS
#define DEC_AXIS