Instrument Neutral Distributed Interface INDI  2.0.2
lx200ap_legacy.cpp
Go to the documentation of this file.
1 /*
2  Astro-Physics INDI driver
3 
4  Copyright (C) 2014 Jasem Mutlaq
5 
6  Based on INDI Astrophysics Driver by Markus Wildi
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 
23 #include "lx200ap.h"
24 
25 #include "indicom.h"
26 #include "lx200driver.h"
27 #include "lx200apdriver.h"
28 
29 #include <libnova/transform.h>
30 
31 #include <cmath>
32 #include <cstring>
33 #include <unistd.h>
34 #include <termios.h>
35 
36 #define MOUNT_TAB "Mount"
37 
38 /* Constructor */
40 {
41  setLX200Capability(LX200_HAS_PULSE_GUIDING);
42  SetTelescopeCapability(GetTelescopeCapability() | TELESCOPE_HAS_PIER_SIDE | TELESCOPE_HAS_PEC | TELESCOPE_CAN_CONTROL_TRACK
43  | TELESCOPE_HAS_TRACK_RATE, 4);
44 
45  sendLocationOnStartup = false;
46  sendTimeOnStartup = false;
47 }
48 
50 {
51  return (const char *)"AstroPhysics";
52 }
53 
55 {
57 
59 
60  IUFillSwitch(&StartUpS[0], "COLD", "Cold", ISS_OFF);
61  IUFillSwitch(&StartUpS[1], "WARM", "Warm", ISS_OFF);
62  IUFillSwitchVector(&StartUpSP, StartUpS, 2, getDeviceName(), "STARTUP", "Mount init.", MAIN_CONTROL_TAB, IP_RW,
63  ISR_1OFMANY, 0, IPS_IDLE);
64 
65  IUFillNumber(&HourangleCoordsN[0], "HA", "HA H:M:S", "%10.6m", 0., 24., 0., 0.);
66  IUFillNumber(&HourangleCoordsN[1], "DEC", "Dec D:M:S", "%10.6m", -90.0, 90.0, 0., 0.);
67  IUFillNumberVector(&HourangleCoordsNP, HourangleCoordsN, 2, getDeviceName(), "HOURANGLE_COORD", "Hourangle Coords",
69 
70  IUFillNumber(&HorizontalCoordsN[0], "AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0.);
71  IUFillNumber(&HorizontalCoordsN[1], "ALT", "Alt D:M:S", "%10.6m", -90., 90., 0., 0.);
73  "Horizontal Coords", MAIN_CONTROL_TAB, IP_RW, 120, IPS_IDLE);
74 
75 
76  // Max rate is 999.99999X for the GTOCP4.
77  // Using :RR998.9999# just to be safe. 15.041067*998.99999 = 15026.02578
78  TrackRateN[AXIS_RA].min = -15026.0258;
79  TrackRateN[AXIS_RA].max = 15026.0258;
80  TrackRateN[AXIS_DE].min = -998.9999;
81  TrackRateN[AXIS_DE].max = 998.9999;
82 
83  // Motion speed of axis when pressing NSWE buttons
84  IUFillSwitch(&SlewRateS[0], "12", "12x", ISS_OFF);
85  IUFillSwitch(&SlewRateS[1], "64", "64x", ISS_ON);
86  IUFillSwitch(&SlewRateS[2], "600", "600x", ISS_OFF);
87  IUFillSwitch(&SlewRateS[3], "1200", "1200x", ISS_OFF);
88  IUFillSwitchVector(&SlewRateSP, SlewRateS, 4, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB, IP_RW,
89  ISR_1OFMANY, 0, IPS_IDLE);
90 
91  // Slew speed when performing regular GOTO
92  IUFillSwitch(&APSlewSpeedS[0], "600", "600x", ISS_ON);
93  IUFillSwitch(&APSlewSpeedS[1], "900", "900x", ISS_OFF);
94  IUFillSwitch(&APSlewSpeedS[2], "1200", "1200x", ISS_OFF);
96  0, IPS_IDLE);
97 
98  IUFillSwitch(&SwapS[0], "NS", "North/South", ISS_OFF);
99  IUFillSwitch(&SwapS[1], "EW", "East/West", ISS_OFF);
100  IUFillSwitchVector(&SwapSP, SwapS, 2, getDeviceName(), "SWAP", "Swap buttons", MOTION_TAB, IP_RW, ISR_1OFMANY, 0,
101  IPS_IDLE);
102 
103  IUFillSwitch(&SyncCMRS[USE_REGULAR_SYNC], ":CM#", ":CM#", ISS_OFF);
104  IUFillSwitch(&SyncCMRS[USE_CMR_SYNC], ":CMR#", ":CMR#", ISS_ON);
106  IPS_IDLE);
107 
108  // guide speed
109  IUFillSwitch(&APGuideSpeedS[0], "0.25", "0.25x", ISS_OFF);
110  IUFillSwitch(&APGuideSpeedS[1], "0.5", "0.50x", ISS_OFF);
111  IUFillSwitch(&APGuideSpeedS[2], "1.0", "1.0x", ISS_ON);
113  0, IPS_IDLE);
114 
115  IUFillText(&VersionT[0], "Number", "", nullptr);
116  IUFillTextVector(&VersionTP, VersionT, 1, getDeviceName(), "Firmware Info", "", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
117 
118  IUFillText(&DeclinationAxisT[0], "RELHA", "rel. to HA", "undefined");
119  IUFillTextVector(&DeclinationAxisTP, DeclinationAxisT, 1, getDeviceName(), "DECLINATIONAXIS", "Declination axis",
120  MOUNT_TAB, IP_RO, 0, IPS_IDLE);
121 
122  // Slew threshold
123  IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0);
124  IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
126  IPS_IDLE);
127 
129 
130  return true;
131 }
132 
133 void LX200AstroPhysics::ISGetProperties(const char *dev)
134 {
136 
137  /*
138  if (isConnected())
139  {
140  defineProperty(&StartUpSP);
141  defineProperty(&VersionTP);
142 
143  //defineProperty(&DeclinationAxisTP);
144 
145  // Motion group
146  defineProperty(&APSlewSpeedSP);
147  defineProperty(&SwapSP);
148  defineProperty(&SyncCMRSP);
149  defineProperty(&APGuideSpeedSP);
150  defineProperty(&SlewAccuracyNP);
151 
152  LOG_INFO("Please initialize the mount before issuing any command.");
153  }
154  */
155 }
156 
158 {
160 
161  if (isConnected())
162  {
165 
166  //defineProperty(&DeclinationAxisTP);
167 
168  /* Motion group */
174 
175  LOG_INFO("Please initialize the mount before issuing any command.");
176  }
177  else
178  {
181  //deleteProperty(DeclinationAxisTP.name);
187  }
188 
189  return true;
190 }
191 
192 bool LX200AstroPhysics::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
193 {
194  int err = 0;
195 
196  // ignore if not ours //
197  if (strcmp(getDeviceName(), dev))
198  return false;
199 
200  // ============================================================
201  // Satisfy AP mount initialization, see AP key pad manual p. 76
202  // ============================================================
203  if (!strcmp(name, StartUpSP.name))
204  {
205  int switch_nr;
206 
207  IUUpdateSwitch(&StartUpSP, states, names, n);
208 
209  if (initStatus == MOUNTNOTINITIALIZED)
210  {
211  if (timeUpdated == false || locationUpdated == false)
212  {
214  LOG_ERROR("Time and location must be set before mount initialization is invoked.");
215  IDSetSwitch(&StartUpSP, nullptr);
216  return false;
217  }
218 
219  if (StartUpSP.sp[0].s == ISS_ON) // do it only in case a power on (cold start)
220  {
221  if (setBasicDataPart1() == false)
222  {
224  IDSetSwitch(&StartUpSP, "Cold mount initialization failed.");
225  return false;
226  }
227  }
228 
229  initStatus = MOUNTINITIALIZED;
230 
231  if (isSimulation())
232  {
233  SlewRateSP.s = IPS_OK;
234  IDSetSwitch(&SlewRateSP, nullptr);
235 
237  IDSetSwitch(&APSlewSpeedSP, nullptr);
238 
239  IUSaveText(&VersionT[0], "1.0");
240  VersionTP.s = IPS_OK;
241  IDSetText(&VersionTP, nullptr);
242 
243  StartUpSP.s = IPS_OK;
244  IDSetSwitch(&StartUpSP, "Mount initialized.");
245 
246  //currentRA = 0;
247  //currentDEC = 90;
248  }
249  else
250  {
251  // Make sure that the mount is setup according to the properties
252  switch_nr = IUFindOnSwitchIndex(&TrackModeSP);
253 
254  if ( (err = selectAPTrackingMode(PortFD, switch_nr)) < 0)
255  {
256  LOGF_ERROR("StartUpSP: Error setting tracking mode (%d).", err);
257  return false;
258  }
259 
261 
262  // On most mounts SlewRateS defines the MoveTo AND Slew (GOTO) speeds
263  // lx200ap is different - some of the MoveTo speeds are not VALID
264  // Slew speeds so we have to keep two lists.
265  //
266  // SlewRateS is used as the MoveTo speed
267  switch_nr = IUFindOnSwitchIndex(&SlewRateSP);
268  if ( (err = selectAPMoveToRate(PortFD, switch_nr)) < 0)
269  {
270  LOGF_ERROR("StartUpSP: Error setting move rate (%d).", err);
271  return false;
272  }
273 
274  SlewRateSP.s = IPS_OK;
275  IDSetSwitch(&SlewRateSP, nullptr);
276 
277  // APSlewSpeedsS defines the Slew (GOTO) speeds valid on the AP mounts
278  switch_nr = IUFindOnSwitchIndex(&APSlewSpeedSP);
279  if ( (err = selectAPSlewRate(PortFD, switch_nr)) < 0)
280  {
281  LOGF_ERROR("StartUpSP: Error setting slew to rate (%d).", err);
282  return false;
283  }
285  IDSetSwitch(&APSlewSpeedSP, nullptr);
286 
289 
290  // make a IDSet in order the dome controller is aware of the initial values
293 
295 
296  char versionString[64];
297  getAPVersionNumber(PortFD, versionString);
298  VersionTP.s = IPS_OK;
299  IUSaveText(&VersionT[0], versionString);
300  IDSetText(&VersionTP, nullptr);
301 
302  // TODO check controller type here
303  INDI_UNUSED(controllerType);
304  INDI_UNUSED(servoType);
305  //controllerType = ...;
306 
307  StartUpSP.s = IPS_OK;
308  IDSetSwitch(&StartUpSP, "Mount initialized.");
309 
310  }
311  }
312  else
313  {
314  StartUpSP.s = IPS_OK;
315  IDSetSwitch(&StartUpSP, "Mount is already initialized.");
316  }
317  return true;
318  }
319 
320  // =======================================
321  // Swap Buttons
322  // =======================================
323  if (!strcmp(name, SwapSP.name))
324  {
325  int currentSwap;
326 
328  IUUpdateSwitch(&SwapSP, states, names, n);
329  currentSwap = IUFindOnSwitchIndex(&SwapSP);
330 
331  if ((!isSimulation() && (err = swapAPButtons(PortFD, currentSwap)) < 0))
332  {
333  LOGF_ERROR("Error swapping buttons (%d).", err);
334  return false;
335  }
336 
337  SwapS[0].s = ISS_OFF;
338  SwapS[1].s = ISS_OFF;
339  SwapSP.s = IPS_OK;
340  IDSetSwitch(&SwapSP, nullptr);
341  return true;
342  }
343 
344  // ===========================================================
345  // GOTO ("slew") Speed.
346  // ===========================================================
347  if (!strcmp(name, APSlewSpeedSP.name))
348  {
349  IUUpdateSwitch(&APSlewSpeedSP, states, names, n);
350  int slewRate = IUFindOnSwitchIndex(&APSlewSpeedSP);
351 
352  if (!isSimulation() && (err = selectAPSlewRate(PortFD, slewRate) < 0))
353  {
354  LOGF_ERROR("Error setting move to rate (%d).", err);
355  return false;
356  }
357 
359  IDSetSwitch(&APSlewSpeedSP, nullptr);
360  return true;
361  }
362 
363  // ===========================================================
364  // Guide Speed.
365  // ===========================================================
366  if (!strcmp(name, APGuideSpeedSP.name))
367  {
368  IUUpdateSwitch(&APGuideSpeedSP, states, names, n);
369  int guideRate = IUFindOnSwitchIndex(&APGuideSpeedSP);
370 
371  if (!isSimulation() && (err = selectAPGuideRate(PortFD, guideRate) < 0))
372  {
373  LOGF_ERROR("Error setting guiding to rate (%d).", err);
374  return false;
375  }
376 
378  IDSetSwitch(&APGuideSpeedSP, nullptr);
379  return true;
380  }
381 
382  // =======================================
383  // Choose the appropriate sync command
384  // =======================================
385  if (!strcmp(name, SyncCMRSP.name))
386  {
388  IUUpdateSwitch(&SyncCMRSP, states, names, n);
390  SyncCMRSP.s = IPS_OK;
391  IDSetSwitch(&SyncCMRSP, nullptr);
392  return true;
393  }
394 
395  // =======================================
396  // Choose the PEC playback mode
397  // =======================================
398  if (!strcmp(name, PECStateSP.name))
399  {
401  IUUpdateSwitch(&PECStateSP, states, names, n);
403 
404  int pecstate = IUFindOnSwitchIndex(&PECStateSP);
405 
406  if (!isSimulation() && (err = selectAPPECState(PortFD, pecstate) < 0))
407  {
408  LOGF_ERROR("Error setting PEC state (%d).", err);
409  return false;
410  }
411 
412  PECStateSP.s = IPS_OK;
413  IDSetSwitch(&PECStateSP, nullptr);
414 
415  return true;
416  }
417 
418  return LX200Generic::ISNewSwitch(dev, name, states, names, n);
419 }
420 
421 /**************************************************************************************
422 **
423 ***************************************************************************************/
424 bool LX200AstroPhysics::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
425 {
426  if (strcmp(getDeviceName(), dev))
427  return false;
428 
429  // Update slew precision limit
430  if (!strcmp(name, SlewAccuracyNP.name))
431  {
432  if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
433  return false;
434 
436 
437  if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
438  IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
439 
440  IDSetNumber(&SlewAccuracyNP, nullptr);
441  return true;
442  }
443 
444  return LX200Generic::ISNewNumber(dev, name, values, names, n);
445 }
446 
447 bool LX200AstroPhysics::isMountInit()
448 {
449  return (StartUpSP.s != IPS_IDLE);
450 }
451 
453 {
454  if (!isMountInit())
455  return false;
456 
457  if (isSimulation())
458  {
459  mountSim();
460  return true;
461  }
462 
464  {
465  EqNP.s = IPS_ALERT;
466  IDSetNumber(&EqNP, "Error reading RA/DEC.");
467  return false;
468  }
469 
470  if (TrackState == SCOPE_SLEWING)
471  {
472  double dx = targetRA - currentRA;
473  double dy = targetDEC - currentDEC;
474 
475  // Wait until acknowledged or within threshold
476  if (fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0))
477  {
479  LOG_INFO("Slew is complete. Tracking...");
480  }
481  }
482  else if (TrackState == SCOPE_PARKING)
483  {
484  double currentAlt, currentAz;
485  if (getLX200Az(PortFD, &currentAz) < 0 || getLX200Alt(PortFD, &currentAlt) < 0)
486  {
487  EqNP.s = IPS_ALERT;
488  IDSetNumber(&EqNP, "Error reading Az/Alt.");
489  return false;
490  }
491 
492  double dx = GetAxis1Park() - currentAz;
493  double dy = GetAxis2Park() - currentAlt;
494 
495  LOGF_DEBUG("Parking... targetAz: %g currentAz: %g dx: %g targetAlt: %g currentAlt: %g dy: %g", GetAxis1Park(),
496  currentAz, dx, GetAxis2Park(), currentAlt, dy);
497 
498  if (fabs(dx) <= (SlewAccuracyN[0].value / (60.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0))
499  {
500  LOG_DEBUG("Parking slew is complete. Asking astrophysics mount to park...");
501 
502  if (!isSimulation() && setAPPark(PortFD) < 0)
503  {
504  LOG_ERROR("Parking Failed.");
505  return false;
506  }
507 
508  SetParked(true);
509  }
510  }
511 
513 
514  syncSideOfPier();
515 
516  return true;
517 }
518 
519 bool LX200AstroPhysics::setBasicDataPart0()
520 {
521  int err;
522  //struct ln_date utm;
523  //struct ln_zonedate ltm;
524 
525  if (isSimulation() == true)
526  {
527  LOG_INFO("setBasicDataPart0 simulation complete.");
528  return true;
529  }
530 
531  if ((err = setAPClearBuffer(PortFD)) < 0)
532  {
533  LOGF_ERROR("Error clearing the buffer (%d): %s", err, strerror(err));
534  return false;
535  }
536 
537  if ((err = setAPLongFormat(PortFD)) < 0)
538  {
539  LOGF_ERROR("Error setting long format failed (%d): %s", err, strerror(err));
540  return false;
541  }
542 
543  if ((err = setAPBackLashCompensation(PortFD, 0, 0, 0)) < 0)
544  {
545  // It seems we need to send it twice before it works!
546  if ((err = setAPBackLashCompensation(PortFD, 0, 0, 0)) < 0)
547  {
548  LOGF_ERROR("Error setting back lash compensation (%d): %s.", err, strerror(err));
549  return false;
550  }
551  }
552 
553  // Detect and set fomat. It should be LONG.
555 
556  return true;
557 }
558 
559 bool LX200AstroPhysics::setBasicDataPart1()
560 {
561  int err = 0;
562 
563  if (InitPark())
564  {
565  // If loading parking data is successful, we just set the default parking values.
566  SetAxis1ParkDefault(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
568  }
569  else
570  {
571  // Otherwise, we set all parking data to default in case no parking data is found.
572  SetAxis1Park(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
574 
575  SetAxis1ParkDefault(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
577  }
578 
579  // Unpark
580  UnPark();
581 
582  // Stop
583  if (!isSimulation() && (err = setAPMotionStop(PortFD)) < 0)
584  {
585  LOGF_ERROR("Stop motion (:Q#) failed, check the mount (%d): %s", err, strerror(err));
586  return false;
587  }
588 
589  // AP always track after unpark? Must check
591 
592  return true;
593 }
594 
595 bool LX200AstroPhysics::Goto(double r, double d)
596 {
597  const struct timespec timeout = {0, 100000000L};
598 
599  targetRA = r;
600  targetDEC = d;
601  char RAStr[64], DecStr[64];
602 
603  fs_sexa(RAStr, targetRA, 2, 3600);
604  fs_sexa(DecStr, targetDEC, 2, 3600);
605 
606  // If moving, let's stop it first.
607  if (EqNP.s == IPS_BUSY)
608  {
609  if (!isSimulation() && abortSlew(PortFD) < 0)
610  {
611  AbortSP.s = IPS_ALERT;
612  IDSetSwitch(&AbortSP, "Abort slew failed.");
613  return false;
614  }
615 
616  AbortSP.s = IPS_OK;
617  EqNP.s = IPS_IDLE;
618  IDSetSwitch(&AbortSP, "Slew aborted.");
619  IDSetNumber(&EqNP, nullptr);
620 
622  {
625  EqNP.s = IPS_IDLE;
628  IDSetSwitch(&MovementNSSP, nullptr);
629  IDSetSwitch(&MovementWESP, nullptr);
630  }
631 
632  // sleep for 100 mseconds
633  nanosleep(&timeout, nullptr);
634  }
635 
636  if (!isSimulation())
637  {
639  {
640  EqNP.s = IPS_ALERT;
641  IDSetNumber(&EqNP, "Error setting RA/DEC.");
642  return false;
643  }
644 
645  int err = 0;
646 
647  /* Slew reads the '0', that is not the end of the slew */
648  if ((err = Slew(PortFD)))
649  {
650  EqNP.s = IPS_ALERT;
651  IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
652  slewError(err);
653  return false;
654  }
655  }
656 
658  //EqNP.s = IPS_BUSY;
659 
660  LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
661  return true;
662 }
663 
664 
665 int LX200AstroPhysics::SendPulseCmd(int8_t direction, uint32_t duration_msec)
666 {
667  return APSendPulseCmd(PortFD, direction, duration_msec);
668 }
669 
670 
672 {
673  return setBasicDataPart0();
674 }
675 
677 {
678  timeUpdated = false;
679  locationUpdated = false;
680 
681  return LX200Generic::Disconnect();
682 }
683 
684 bool LX200AstroPhysics::Sync(double ra, double dec)
685 {
686  char syncString[256];
687 
688  int syncType = IUFindOnSwitchIndex(&SyncCMRSP);
689 
690  if (!isSimulation())
691  {
692  if (setAPObjectRA(PortFD, ra) < 0 || setAPObjectDEC(PortFD, dec) < 0)
693  {
694  EqNP.s = IPS_ALERT;
695  IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync.");
696  return false;
697  }
698 
699  bool syncOK = true;
700 
701  switch (syncType)
702  {
703  case USE_REGULAR_SYNC:
704  if (::Sync(PortFD, syncString) < 0)
705  syncOK = false;
706  break;
707 
708  case USE_CMR_SYNC:
709  if (APSyncCMR(PortFD, syncString) < 0)
710  syncOK = false;
711  break;
712 
713  default:
714  break;
715  }
716 
717  if (syncOK == false)
718  {
719  EqNP.s = IPS_ALERT;
720  IDSetNumber(&EqNP, "Synchronization failed.");
721  return false;
722  }
723 
724  }
725 
726  currentRA = ra;
727  currentDEC = dec;
728 
729  LOGF_DEBUG("%s Synchronization successful %s", (syncType == USE_REGULAR_SYNC ? "CM" : "CMR"), syncString);
730  LOG_INFO("Synchronization successful.");
731 
732  EqNP.s = IPS_OK;
733 
735 
736  return true;
737 }
738 
739 bool LX200AstroPhysics::updateTime(ln_date *utc, double utc_offset)
740 {
741  struct ln_zonedate ltm;
742 
743  if (isSimulation())
744  {
745  timeUpdated = true;
746  return true;
747  }
748 
749  ln_date_to_zonedate(utc, &ltm, utc_offset * 3600.0);
750 
751  JD = ln_get_julian_day(utc);
752 
753  LOGF_DEBUG("New JD is %.2f", JD);
754 
755  // Set Local Time
756  if (setLocalTime(PortFD, ltm.hours, ltm.minutes, (int)ltm.seconds) < 0)
757  {
758  LOG_ERROR("Error setting local time.");
759  return false;
760  }
761 
762  LOGF_DEBUG("Set Local Time %02d:%02d:%02d is successful.", ltm.hours, ltm.minutes,
763  (int)ltm.seconds);
764 
765  if (setCalenderDate(PortFD, ltm.days, ltm.months, ltm.years) < 0)
766  {
767  LOG_ERROR("Error setting local date.");
768  return false;
769  }
770 
771  LOGF_DEBUG("Set Local Date %02d/%02d/%02d is successful.", ltm.days, ltm.months, ltm.years);
772 
773  if (setAPUTCOffset(PortFD, fabs(utc_offset)) < 0)
774  {
775  LOG_ERROR("Error setting UTC Offset.");
776  return false;
777  }
778 
779  LOGF_DEBUG("Set UTC Offset %g (always positive for AP) is successful.", fabs(utc_offset));
780 
781  LOG_INFO("Time updated.");
782 
783  timeUpdated = true;
784 
785  return true;
786 }
787 
788 bool LX200AstroPhysics::updateLocation(double latitude, double longitude, double elevation)
789 {
790  INDI_UNUSED(elevation);
791 
792  if (isSimulation())
793  {
794  locationUpdated = true;
795  return true;
796  }
797 
798  if (!isSimulation() && setAPSiteLongitude(PortFD, 360.0 - longitude) < 0)
799  {
800  LOG_ERROR("Error setting site longitude coordinates");
801  return false;
802  }
803 
804  if (!isSimulation() && setAPSiteLatitude(PortFD, latitude) < 0)
805  {
806  LOG_ERROR("Error setting site latitude coordinates");
807  return false;
808  }
809 
810  char l[32], L[32];
811  fs_sexa(l, latitude, 3, 3600);
812  fs_sexa(L, longitude, 4, 3600);
813 
814  LOGF_INFO("Site location updated to Lat %.32s - Long %.32s", l, L);
815 
816  locationUpdated = true;
817 
818  return true;
819 }
820 
821 void LX200AstroPhysics::debugTriggered(bool enable)
822 {
823  INDI_UNUSED(enable);
826 }
827 
828 
829 // For most mounts the SetSlewRate() method sets both the MoveTo and Slew (GOTO) speeds.
830 // For AP mounts these two speeds are handled separately - so SetSlewRate() actually sets the MoveTo speed for AP mounts - confusing!
831 // ApSetSlew
832 bool LX200AstroPhysics::SetSlewRate(int index)
833 {
834  if (!isSimulation() && selectAPMoveToRate(PortFD, index) < 0)
835  {
837  IDSetSwitch(&SlewRateSP, "Error setting slew mode.");
838  return false;
839  }
840 
841  SlewRateSP.s = IPS_OK;
842  IDSetSwitch(&SlewRateSP, nullptr);
843  return true;
844 }
845 
847 {
848  if (initStatus == MOUNTNOTINITIALIZED)
849  {
850  LOG_WARN("You must initialize the mount before parking.");
851  return false;
852  }
853 
854  double parkAz = GetAxis1Park();
855  double parkAlt = GetAxis2Park();
856 
857  char AzStr[16], AltStr[16];
858  fs_sexa(AzStr, parkAz, 2, 3600);
859  fs_sexa(AltStr, parkAlt, 2, 3600);
860  LOGF_DEBUG("Parking to Az (%s) Alt (%s)...", AzStr, AltStr);
861 
862  if (isSimulation())
863  {
864  INDI::IEquatorialCoordinates equatorialCoords {0, 0};
865  INDI::IHorizontalCoordinates horizontalCoords {parkAz, parkAlt};
866  INDI::HorizontalToEquatorial(&horizontalCoords, &m_Location, ln_get_julian_from_sys(), &equatorialCoords);
867  Goto(equatorialCoords.rightascension, equatorialCoords.declination);
868  }
869  else
870  {
871  if (setAPObjectAZ(PortFD, parkAz) < 0 || setAPObjectAlt(PortFD, parkAlt) < 0)
872  {
873  LOG_ERROR("Error setting Az/Alt.");
874  return false;
875  }
876 
877  int err = 0;
878 
879  /* Slew reads the '0', that is not the end of the slew */
880  if ((err = Slew(PortFD)))
881  {
882  LOGF_ERROR("Error Slewing to Az %s - Alt %s", AzStr, AltStr);
883  slewError(err);
884  return false;
885  }
886  }
887 
888  EqNP.s = IPS_BUSY;
890  LOG_INFO("Parking is in progress...");
891 
892  return true;
893 }
894 
896 {
897  // First we unpark astrophysics
898  if (isSimulation() == false)
899  {
900  if (setAPUnPark(PortFD) < 0)
901  {
902  LOG_ERROR("UnParking Failed.");
903  return false;
904  }
905  }
906 
907  // Then we sync with to our last stored position
908  double parkAz = GetAxis1Park();
909  double parkAlt = GetAxis2Park();
910 
911  char AzStr[16], AltStr[16];
912  fs_sexa(AzStr, parkAz, 2, 3600);
913  fs_sexa(AltStr, parkAlt, 2, 3600);
914  LOGF_DEBUG("Syncing to parked coordinates Az (%s) Alt (%s)...", AzStr, AltStr);
915 
916  if (isSimulation())
917  {
918  INDI::IEquatorialCoordinates equatorialCoords {0, 0};
919  INDI::IHorizontalCoordinates horizontalCoords {parkAz, parkAlt};
920  INDI::HorizontalToEquatorial(&horizontalCoords, &m_Location, ln_get_julian_from_sys(), &equatorialCoords);
921 
922  currentRA = equatorialCoords.rightascension;
923  currentDEC = equatorialCoords.declination;
924  }
925  else
926  {
927  if (setAPObjectAZ(PortFD, parkAz) < 0 || (setAPObjectAlt(PortFD, parkAlt)) < 0)
928  {
929  LOG_ERROR("Error setting Az/Alt.");
930  return false;
931  }
932 
933  char syncString[256];
934  if (APSyncCM(PortFD, syncString) < 0)
935  {
936  LOG_WARN("Sync failed.");
937  return false;
938  }
939  }
940 
941  SetParked(false);
942  return true;
943 }
944 
946 {
948  INDI::IHorizontalCoordinates horizontalCoords {0, 0};
949  INDI::EquatorialToHorizontal(&equatorialCoords, &m_Location, ln_get_julian_from_sys(), &horizontalCoords);
950  double parkAZ = horizontalCoords.azimuth;
951  double parkAlt = horizontalCoords.altitude;
952 
953  char AzStr[16], AltStr[16];
954  fs_sexa(AzStr, parkAZ, 2, 3600);
955  fs_sexa(AltStr, parkAlt, 2, 3600);
956 
957  LOGF_DEBUG("Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr,
958  AltStr);
959 
960  SetAxis1Park(parkAZ);
961  SetAxis2Park(parkAlt);
962 
963  return true;
964 }
965 
967 {
968  // Az = 0 for North hemisphere
969  SetAxis1Park(LocationN[LOCATION_LATITUDE].value > 0 ? 0 : 180);
970 
971  // Alt = Latitude
973 
974  return true;
975 }
976 
977 void LX200AstroPhysics::syncSideOfPier()
978 {
979  const char *cmd = ":pS#";
980  // Response
981  char response[16] = { 0 };
982  int rc = 0, nbytes_read = 0, nbytes_written = 0;
983 
984  LOGF_DEBUG("CMD: <%s>", cmd);
985 
986  tcflush(PortFD, TCIOFLUSH);
987 
988  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
989  {
990  char errmsg[256];
991  tty_error_msg(rc, errmsg, 256);
992  LOGF_ERROR("Error writing to device %s (%d)", errmsg, rc);
993  return;
994  }
995 
996  // Read Side
997  if ((rc = tty_read_section(PortFD, response, '#', 3, &nbytes_read)) != TTY_OK)
998  {
999  char errmsg[256];
1000  tty_error_msg(rc, errmsg, 256);
1001  LOGF_ERROR("Error reading from device %s (%d)", errmsg, rc);
1002  return;
1003  }
1004 
1005  response[nbytes_read - 1] = '\0';
1006 
1007  tcflush(PortFD, TCIOFLUSH);
1008 
1009  LOGF_DEBUG("RES: <%s>", response);
1010 
1011  if (!strcmp(response, "East"))
1013  else if (!strcmp(response, "West"))
1015  else
1016  LOGF_ERROR("Invalid pier side response from device-> %s", response);
1017 
1018 }
1019 
1021 {
1023 
1027 
1028  return true;
1029 }
1030 
1031 bool LX200AstroPhysics::SetTrackMode(uint8_t mode)
1032 {
1033  int err = 0;
1034 
1035  if (mode == TRACK_CUSTOM)
1036  {
1038  {
1039  LOGF_ERROR("Error setting tracking mode (%d).", err);
1040  return false;
1041  }
1042 
1043  return SetTrackRate(TrackRateN[AXIS_RA].value, TrackRateN[AXIS_DE].value);
1044  }
1045 
1046  if (!isSimulation() && (err = selectAPTrackingMode(PortFD, mode)) < 0)
1047  {
1048  LOGF_ERROR("Error setting tracking mode (%d).", err);
1049  return false;
1050  }
1051 
1052  return true;
1053 }
1054 
1055 bool LX200AstroPhysics::SetTrackEnabled(bool enabled)
1056 {
1058 }
1059 
1060 bool LX200AstroPhysics::SetTrackRate(double raRate, double deRate)
1061 {
1062  // Convert to arcsecs/s to AP sidereal multiplier
1063  /*
1064  :RR0.0000# = normal sidereal tracking in RA - similar to :RT2#
1065  :RR+1.0000# = 1 + normal sidereal = 2X sidereal
1066  :RR+9.0000# = 9 + normal sidereal = 10X sidereal
1067  :RR-1.0000# = normal sidereal - 1 = 0 or Stop - similar to :RT9#
1068  :RR-11.0000# = normal sidereal - 11 = -10X sidereal (East at 10X)
1069 
1070  :RD0.0000# = normal zero rate for Dec.
1071  :RD5.0000# = 5 + normal zero rate = 5X sidereal clockwise from above - equivalent to South
1072  :RD-5.0000# = normal zero rate - 5 = 5X sidereal counter-clockwise from above - equivalent to North
1073  */
1074 
1075  double APRARate = (raRate - TRACKRATE_SIDEREAL) / TRACKRATE_SIDEREAL;
1076  double APDERate = deRate / TRACKRATE_SIDEREAL;
1077 
1078  if (!isSimulation())
1079  {
1080  if (setAPRATrackRate(PortFD, APRARate) < 0 || setAPDETrackRate(PortFD, APDERate) < 0)
1081  return false;
1082  }
1083 
1084  return true;
1085 }
1086 
1087 bool LX200AstroPhysics::getUTFOffset(double *offset)
1088 {
1089  if (isSimulation())
1090  {
1091  *offset = 3;
1092  return true;
1093  }
1094 
1095  return (getAPUTCOffset(PortFD, offset) == 0);
1096 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool Disconnect()
Disconnect from device.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
double GetAxis1Park() const
double GetAxis2Park() const
ISwitchVectorProperty PECStateSP
ISwitchVectorProperty TrackModeSP
ISwitchVectorProperty SlewRateSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
INumber TrackRateN[2]
IGeographicCoordinates m_Location
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...
ISwitchVectorProperty MovementWESP
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
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.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: lx200ap.cpp:79
ISwitchVectorProperty StartUpSP
Definition: lx200ap.h:103
ISwitchVectorProperty APSlewSpeedSP
Definition: lx200ap.h:114
virtual bool UnPark() override
Unpark the telescope if already parked.
Definition: lx200ap.cpp:1867
ISwitchVectorProperty APGuideSpeedSP
Definition: lx200ap.h:124
ISwitch APSlewSpeedS[3]
Definition: lx200ap.h:113
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
Definition: lx200ap.cpp:2162
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
Definition: lx200ap.cpp:1673
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
Definition: lx200ap.cpp:2188
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
Definition: lx200ap.cpp:1138
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
Definition: lx200ap.cpp:2201
INumber HorizontalCoordsN[2]
Definition: lx200ap.h:110
ISwitchVectorProperty SwapSP
Definition: lx200ap.h:117
ISwitch APGuideSpeedS[3]
Definition: lx200ap.h:123
virtual bool Park() override
Park the telescope to its home position.
Definition: lx200ap.cpp:1740
virtual const char * getDefaultName() override
Definition: lx200ap.cpp:61
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: lx200ap.cpp:2095
ISwitch SwapS[2]
Definition: lx200ap.h:116
ISwitch SyncCMRS[2]
Definition: lx200ap.h:119
INumberVectorProperty SlewAccuracyNP
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition: lx200ap.cpp:1558
IText VersionT[1]
Definition: lx200ap.h:135
virtual int SendPulseCmd(int8_t direction, uint32_t duration_msec) override
Definition: lx200ap.cpp:1464
IText DeclinationAxisT[1]
ITextVectorProperty VersionTP
Definition: lx200ap.h:136
ISwitch StartUpS[2]
Definition: lx200ap.h:102
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: lx200ap.cpp:2074
virtual bool Handshake() override
perform handshake with device to check communication
Definition: lx200ap.cpp:1469
INumberVectorProperty HorizontalCoordsNP
Definition: lx200ap.h:111
virtual bool getUTFOffset(double *offset) override
Definition: lx200ap.cpp:2228
INumber SlewAccuracyN[2]
virtual bool Disconnect() override
Disconnect from device.
Definition: lx200ap.cpp:1544
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
Definition: lx200ap.cpp:1610
INumber HourangleCoordsN[2]
Definition: lx200ap.h:105
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: lx200ap.cpp:203
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: lx200ap.cpp:506
ISwitchVectorProperty SyncCMRSP
Definition: lx200ap.h:120
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
Definition: lx200ap.cpp:1717
INumberVectorProperty HourangleCoordsNP
Definition: lx200ap.h:106
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: lx200ap.cpp:446
ITextVectorProperty DeclinationAxisTP
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
Definition: lx200ap.cpp:1729
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: lx200ap.cpp:2148
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: lx200ap.cpp:176
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: lx200ap.cpp:850
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void slewError(int slewCode)
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
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 void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
#define setLocalTime(fd, x, y, z)
Definition: ieq45driver.h:141
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
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ AXIS_DE
Definition: indibasetypes.h:36
@ AXIS_RA
Definition: indibasetypes.h:35
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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.
@ TTY_OK
Definition: indicom.h:150
#define TRACKRATE_SIDEREAL
Definition: indicom.h:55
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 IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
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
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MOUNTNOTINITIALIZED
Definition: lx200ap.h:26
#define MOUNTINITIALIZED
Definition: lx200ap.h:27
#define MOUNT_TAB
int selectAPMoveToRate(int fd, int moveToIndex)
int setAPUTCOffset(int fd, double hours)
int setAPSiteLatitude(int fd, double Lat)
void set_lx200ap_name(const char *deviceName, unsigned int debug_level)
int setAPRATrackRate(int fd, double rate)
int setAPObjectRA(int fd, double ra)
int APSyncCMR(int fd, char *matchedObject)
int setAPObjectAlt(int fd, double alt)
int swapAPButtons(int fd, int currentSwap)
int setAPObjectDEC(int fd, double dec)
int APSendPulseCmd(int fd, int direction, int duration_msec)
int selectAPSlewRate(int fd, int slewIndex)
int selectAPPECState(int fd, int pecstate)
int selectAPGuideRate(int fd, int guideRate)
int setAPObjectAZ(int fd, double az)
int APSyncCM(int fd, char *matchedObject)
int getAPUTCOffset(int fd, double *value)
int setAPDETrackRate(int fd, double rate)
int setAPSiteLongitude(int fd, double Long)
int selectAPTrackingMode(int fd, int trackMode)
#define setAPBackLashCompensation(fd, x, y, z)
Definition: lx200apdriver.h:30
#define getAPVersionNumber(fd, x)
Definition: lx200apdriver.h:28
#define setAPClearBuffer(fd)
Definition: lx200apdriver.h:29
#define setAPPark(fd)
Definition: lx200apdriver.h:24
#define AP_TRACKING_OFF
Definition: lx200apdriver.h:36
#define setAPUnPark(fd)
Definition: lx200apdriver.h:25
#define AP_TRACKING_SIDEREAL
Definition: lx200apdriver.h:32
int checkLX200EquatorialFormat(int fd)
int abortSlew(int fd)
int setCalenderDate(int fd, int dd, int mm, int yy, bool addSpace)
int Slew(int fd)
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
@ LX200_24
Definition: lx200driver.h:64
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
#define getLX200Alt(fd, x)
Definition: lx200driver.h:124
#define getLX200Az(fd, x)
Definition: lx200driver.h:125
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
Definition: libastro.cpp:140
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
Definition: libastro.cpp:156
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250