Instrument Neutral Distributed Interface INDI  2.0.2
lx200_TeenAstro.cpp
Go to the documentation of this file.
1 /*
2 
3 LX200_TeenAstro
4 
5 Based on LX200_OnStep and others
6 François Desvallées https://github.com/fdesvallees
7 
8 Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com)
9 
10 This library is free software;
11 you can redistribute it and / or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation;
14 either
15 version 2.1 of the License, or (at your option) any later version.
16 
17 This library is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY;
19 without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22 
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library;
25 if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
27 
28 */
29 
30 #include "lx200_TeenAstro.h"
31 #include <libnova/sidereal_time.h>
32 
33 #include <unistd.h>
34 #include <termios.h>
35 #include <stdlib.h>
36 #include <cerrno>
37 
38 #include <cmath>
39 #include <memory>
40 #include <cstring>
41 #include <mutex>
42 
43 
44 /* Simulation Parameters */
45 #define SLEWRATE 1 /* slew rate, degrees/s */
46 #define SIDRATE 0.004178 /* sidereal rate, degrees/s */
47 
48 #define FIRMWARE_TAB "Firmware data"
49 
50 #define ONSTEP_TIMEOUT 3
51 
52 // Our telescope auto pointer
53 static std::unique_ptr<LX200_TeenAstro> teenAstro(new LX200_TeenAstro());
54 extern std::mutex lx200CommsLock;
55 
56 /*
57  * LX200 TeenAstro constructor
58  */
60 {
61  setVersion(1, 3); // don't forget to update drivers.xml
62 
63  DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE");
64 
69 
70  LOG_DEBUG("Initializing from LX200 TeenAstro device...");
71 }
72 
74 {
75  INDI_UNUSED(enable);
76  setLX200Debug(getDeviceName(), DBG_SCOPE);
77 }
78 
80 {
81  return getDefaultName();
82 }
83 
85 {
86  return "LX200 TeenAstro";
87 }
88 
90 {
91  /* Make sure to init parent properties first */
93 
95 
96  // ============== MAIN_CONTROL_TAB
97 
98  // Tracking Mode
99  AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
100  AddTrackMode("TRACK_SOLAR", "Solar");
101  AddTrackMode("TRACK_LUNAR", "Lunar");
102 
103  // Error Status
104  IUFillText(&ErrorStatusT[0], "Error code", "", "");
105  IUFillTextVector(&ErrorStatusTP, ErrorStatusT, 1, getDeviceName(), "Mount Status", "", MAIN_CONTROL_TAB, IP_RO, 0,
106  IPS_IDLE);
107 
108 
109  // ============== MOTION_TAB
110  // Motion speed of axis when pressing NSWE buttons
111  IUFillSwitch(&SlewRateS[0], "Guide", "Guide Speed", ISS_OFF);
112  IUFillSwitch(&SlewRateS[1], "Slow", "Slow", ISS_OFF);
113  IUFillSwitch(&SlewRateS[2], "Medium", "Medium", ISS_OFF);
114  IUFillSwitch(&SlewRateS[3], "Fast", "Fast", ISS_ON);
115  IUFillSwitch(&SlewRateS[4], "Max", "Max", ISS_OFF);
116  IUFillSwitchVector(&SlewRateSP, SlewRateS, 5, getDeviceName(), "TELESCOPE_SLEW_RATE", "Centering Rate",
118 
119  // ============== GUIDE_TAB
120  // Motion speed of axis when guiding
121  IUFillNumber(&GuideRateN[0], "Guide Rate", "value", "%.2f", 0.0, 1.0, 0.1, INITIAL_GUIDE_RATE);
122  IUFillNumberVector(&GuideRateNP, GuideRateN, 1, getDeviceName(), "TELESCOPE_GUIDE_RATE", "Guide Rate",
123  GUIDE_TAB, IP_RW, 0, IPS_IDLE);
125 
126  // ============== OPTIONS_TAB
127  // Slew threshold
128  IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); // min,max,step,current
129  IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
130  IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), getDeviceName(), "Slew Accuracy", "",
131  OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
132 
133  // ============== SITE_TAB
134  IUFillSwitch(&SiteS[0], "Site 1", "", ISS_OFF);
135  IUFillSwitch(&SiteS[1], "Site 2", "", ISS_OFF);
136  IUFillSwitch(&SiteS[2], "Site 3", "", ISS_OFF);
137  IUFillSwitch(&SiteS[3], "Site 4", "", ISS_OFF);
138  IUFillSwitchVector(&SiteSP, SiteS, 4, getDeviceName(), "Sites", "", SITE_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
139 
140  IUFillText(&SiteNameT[0], "Name", "", "");
141  IUFillTextVector(&SiteNameTP, SiteNameT, 1, getDeviceName(), "Site Name", "", SITE_TAB, IP_RO, 0, IPS_IDLE);
142 
143 
144  // ============== FIRMWARE_TAB
145  IUFillText(&VersionT[0], "Date", "", "");
146  IUFillText(&VersionT[1], "Time", "", "");
147  IUFillText(&VersionT[2], "Number", "", "");
148  IUFillText(&VersionT[3], "Name", "", "");
149  IUFillTextVector(&VersionTP, VersionT, 4, getDeviceName(), "Firmware Info", "", FIRMWARE_TAB, IP_RO, 0, IPS_IDLE);
150 
151  addAuxControls();
153 
154  return true;
155 }
156 void LX200_TeenAstro::ISGetProperties(const char *dev)
157 {
158  if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
159  return;
160 
162 }
163 
165 {
167 
168  if (isConnected())
169  {
170  // Delete inherited controls - too confusing
171  deleteProperty("USEJOYSTICK");
172  deleteProperty("ACTIVE_DEVICES");
173  deleteProperty("DOME_POLICY");
174  deleteProperty("TELESCOPE_HAS_TRACK_RATE");
175  // Main Control
176  defineProperty(&SlewAccuracyNP);
177  defineProperty(&ErrorStatusTP);
178  // Connection
179  // Options
180  // Motion Control
181  defineProperty(&SlewRateSP);
182  defineProperty(&GuideRateNP);
183 
184  // Site Management
186  defineProperty(&SetHomeSP);
187 
188  defineProperty(&SiteSP);
189  defineProperty(&SiteNameTP);
190 
191  // Guide
194 
195  // Firmware Data
196  defineProperty(&VersionTP);
197  getBasicData();
198  }
199  else
200  {
201  // Main Control
202  deleteProperty(SlewAccuracyNP.name);
203  deleteProperty(ErrorStatusTP.name);
204  // Connection
205  // Options
206  // Motion Control
207  deleteProperty(SlewRateSP.name);
208  deleteProperty(GuideRateNP.name);
209  deleteProperty(SiteSP.name);
210  deleteProperty(SiteNameTP.name);
211 
212  // Site Management
214  deleteProperty(SetHomeSP.name);
215  // Guide
218  // Firmware Data
219  deleteProperty(VersionTP.name);
220  }
221  return true;
222 }
223 
224 
226 {
227  if (isSimulation())
228  {
229  LOG_INFO("Simulated Connection.");
230  return true;
231  }
232 
233  if (getLX200RA(PortFD, &currentRA) != 0)
234  {
235  LOG_ERROR("Error communicating with telescope.");
236  return false;
237  }
238  LOG_INFO("TeenAstro is Connected");
239  return true;
240 }
241 
242 /*
243  * ReadScopeStatus
244  * Called when polling the mount about once per second
245  */
247 {
248  if (isSimulation())
249  {
250  mountSim();
251  return true;
252  }
253  if (!isConnected())
254  return false;
255 
256  if (getLX200RA(PortFD, &currentRA) < 0 || getLX200DEC(PortFD, &currentDEC) < 0)
257  {
258  EqNP.s = IPS_ALERT;
259  return false;
260  }
261 
262  if (TrackState == SCOPE_SLEWING)
263  {
264  // Check if LX200 is done slewing
265  if (isSlewComplete())
266  {
268  LOG_INFO("Slew is complete. Tracking...");
269  }
270  }
271  else if (TrackState == SCOPE_PARKING)
272  {
273  LOG_INFO("Parking");
274  }
275 
276  // update mount status
277  getCommandString(PortFD, OSStat, statusCommand); // returns a string containg controller status
278  if (OSStat[15] != '0')
279  {
280  updateMountStatus(OSStat[15]); // error
281  }
282  if (strcmp(OSStat, OldOSStat) != 0) // if status changed
283  {
284  handleStatusChange();
285  snprintf(OldOSStat, sizeof(OldOSStat), "%s", OSStat);
286  }
287 #if 0
288  // HACK: simulate small change in RA to force update of hour angle (EKOS bug)
289  static bool incRa;
290  if (incRa)
291  {
292  currentRA += 0.000001; // 0.02 arc sec
293  incRa = false;
294  }
295  else
296  {
297  incRa = true;
298  }
299 #endif
300 
301  NewRaDec(currentRA, currentDEC);
302 
303  return true;
304 }
305 
306 /*
307  * Use OSStat to detect status change - handle each byte separately
308  * called by ReadScopeStatus()
309  */
310 void LX200_TeenAstro::handleStatusChange(void)
311 {
312  LOGF_DEBUG ("Status Change: %s", OSStat);
313 
314  if (OSStat[0] != OldOSStat[0])
315  {
316  if (OSStat[0] == '0')
317  {
319  }
320  else if (OSStat[0] == '1')
321  {
323  }
324  else if (OSStat[0] == '2' || OSStat[0] == '3' )
325  {
327  }
328  }
329 
330 
331  // Byte 2 is park status
332  if (OSStat[2] != OldOSStat[2])
333  {
334  if (OSStat[2] == 'P')
335  {
336  SetParked(true); // defaults to TrackState=SCOPE_PARKED
337  }
338  else
339  {
340  SetParked(false);
341  // SetTrackEnabled(false); //disable since TeenAstro enables it by default
342  }
343  }
344  // Byte 4 is current slew rate
345  if (OSStat[4] != OldOSStat[4])
346  {
347  updateSlewRate();
348  }
349 
350 
351  // Byte 13 is pier side
352  if (OSStat[13] != OldOSStat[13])
353  {
355  }
356  // Byte 15 is the error status
357  if (OSStat[15] != OldOSStat[15])
358  {
359  updateMountStatus(OSStat[15]);
360  }
361 }
362 
363 /*
364  * Mount Error status
365  * 0:ERR_NONE, 1: ERR_MOTOR_FAULT, 2: ERR_ALT, 3: ERR_LIMIT_SENSE
366  * 4: ERR_AXIS2,5: ERR_AZM, 6: ERR_UNDER_POLE, 7: ERR_MERIDIAN, 8: ERR_SYNC
367  */
368 void LX200_TeenAstro::updateMountStatus(char status)
369 {
370  static const char *errCodes[9] = {"ERR_NONE", "ERR_MOTOR_FAULT", "ERR_ALT", "ERR_LIMIT_SENSE",
371  "ERR_AXIS2", "ERR_AZM", "ERR_UNDER_POLE", "ERR_MERIDIAN", "ERR_SYNC"
372  };
373 
374  if (status < '0' || status > '9')
375  {
376  return;
377  }
378  if (status == '0')
379  {
380  ErrorStatusTP.s = IPS_OK;
381  }
382  else
383  {
384  ErrorStatusTP.s = IPS_ALERT;
385  TrackState = SCOPE_IDLE; // Tell Ekos mount is not tracking anymore
386  }
387  IUSaveText(&ErrorStatusT[0], errCodes[status - '0']);
388  IDSetText(&ErrorStatusTP, nullptr);
389 }
390 
391 /*
392  * Goto target
393  * Use standard lx200driver command (:Sr #)
394  * Set state to slewing
395  */
396 bool LX200_TeenAstro::Goto(double r, double d)
397 {
398  targetRA = r;
399  targetDEC = d;
400  char RAStr[64] = {0}, DecStr[64] = {0};
401 
402  fs_sexa(RAStr, targetRA, 2, 3600);
403  fs_sexa(DecStr, targetDEC, 2, 3600);
404 
405  // If moving, let's stop it first.
406  if (EqNP.s == IPS_BUSY)
407  {
408  if (!isSimulation() && abortSlew(PortFD) < 0)
409  {
410  AbortSP.s = IPS_ALERT;
411  IDSetSwitch(&AbortSP, "Abort slew failed.");
412  return false;
413  }
414 
415  AbortSP.s = IPS_OK;
416  EqNP.s = IPS_IDLE;
417  IDSetSwitch(&AbortSP, "Slew aborted.");
418  IDSetNumber(&EqNP, nullptr);
419 
420  // sleep for 100 mseconds
421  const struct timespec ms100_delay = {.tv_sec = 0, .tv_nsec = 100000000};
422  nanosleep(&ms100_delay, NULL);
423  }
424 
425  if (!isSimulation())
426  {
427  if (setObjectRA(PortFD, targetRA) < 0 || (setObjectDEC(PortFD, targetDEC)) < 0) // standard LX200 command
428  {
429  EqNP.s = IPS_ALERT;
430  IDSetNumber(&EqNP, "Error setting RA/DEC.");
431  return false;
432  }
433 
434  int err = 0;
435 
436  /* Slew reads the '0', that is not the end of the slew */
437  if ((err = Slew(PortFD)))
438  {
439  EqNP.s = IPS_ALERT;
440  IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
441  slewError(err);
442  return false;
443  }
444  }
445 
447  EqNP.s = IPS_BUSY;
448 
449  LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
450  return true;
451 }
452 
453 bool LX200_TeenAstro::isSlewComplete()
454 {
455  const double dx = targetRA - currentRA;
456  const double dy = targetDEC - currentDEC;
457  return fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0);
458 }
459 
461 {
462  if (isSimulation())
463  return true;
464 
465  bool rc = (selectTrackingMode(PortFD, mode) == 0);
466 
467  return rc;
468 }
469 
470 /*
471  * Sync - synchronizes the telescope with its currently selected database object coordinates
472  */
473 bool LX200_TeenAstro::Sync(double ra, double dec)
474 {
475  char syncString[256] = {0};
476 
477  // goto target
478  if (!isSimulation() && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0))
479  {
480  EqNP.s = IPS_ALERT;
481  IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync.");
482  return false;
483  }
484 
485  // Use the parent Sync() function (lx200driver.cpp)
486  if (!isSimulation() && ::Sync(PortFD, syncString) < 0)
487  {
488  EqNP.s = IPS_ALERT;
489  IDSetNumber(&EqNP, "Synchronization failed.");
490  return false;
491  }
492 
493  currentRA = ra;
494  currentDEC = dec;
495 
496  LOG_INFO("Synchronization successful.");
497  EqNP.s = IPS_OK;
499 
500  return true;
501 }
502 
503 
504 
505 //======================== Parking =======================
507 {
508  char response[RB_MAX_LEN];
509 
510  if (isSimulation())
511  {
512  LOG_DEBUG("SetCurrentPark: CMD <:hQ>");
513  return true;
514  }
515 
516  if (getCommandString(PortFD, response, ":hQ#") < 0)
517  {
518  LOGF_WARN("===CMD==> Set Park Pos %s", response);
519  return false;
520  }
523  LOG_WARN("Park Value set to current position");
524  return true;
525 }
526 
528 {
529  char response[RB_MAX_LEN];
530 
531  if (isSimulation())
532  {
533  LOG_DEBUG("UnPark: CMD <:hR>");
535  EqNP.s = IPS_OK;
536  return true;
537  }
538  if (getCommandString(PortFD, response, ":hR#") < 0)
539  {
540  return false;
541  }
542  SetParked(false);
543 
544  return true;
545 }
546 
548 {
549  if (isSimulation())
550  {
551  LOG_DEBUG("SlewToPark: CMD <:hP>");
553  EqNP.s = IPS_OK;
554  return true;
555  }
556 
557  // If scope is moving, let's stop it first.
558  if (EqNP.s == IPS_BUSY)
559  {
560  if (abortSlew(PortFD) < 0)
561  {
562  Telescope::AbortSP.s = IPS_ALERT;
563  IDSetSwitch(&(Telescope::AbortSP), "Abort slew failed.");
564  return false;
565  }
566  Telescope::AbortSP.s = IPS_OK;
567  EqNP.s = IPS_IDLE;
568  IDSetSwitch(&(Telescope::AbortSP), "Slew aborted.");
569  IDSetNumber(&EqNP, nullptr);
570 
572  {
575  EqNP.s = IPS_IDLE;
578 
579  IDSetSwitch(&MovementNSSP, nullptr);
580  IDSetSwitch(&MovementWESP, nullptr);
581  }
582  }
583  if (slewToPark(PortFD) < 0) // slewToPark is a macro (lx200driver.h)
584  {
585  ParkSP.s = IPS_ALERT;
586  IDSetSwitch(&ParkSP, "Parking Failed.");
587  return false;
588  }
589  ParkSP.s = IPS_BUSY;
591  LOG_INFO("Parking is in progress...");
592 
593  return true;
594 }
595 
596 
597 /*
598  * updateLocation: not used - use hand controller to update
599  */
600 bool LX200_TeenAstro::updateLocation(double latitude, double longitude, double elevation)
601 {
602  INDI_UNUSED(latitude);
603  INDI_UNUSED(longitude);
604  INDI_UNUSED(elevation);
605 
606  return true;
607 }
608 
609 void LX200_TeenAstro::updateSlewRate()
610 {
611  int slewRateIndex;
612 
613  // get current slew rate
614  if (getSlewRate(&slewRateIndex))
615  {
616  LOGF_INFO("current slew rate : %d", slewRateIndex);
617  IUResetSwitch(&SlewRateSP);
618  SlewRateS[slewRateIndex].s = ISS_ON;
619  SlewRateSP.s = IPS_OK;
620  IDSetSwitch(&SlewRateSP, nullptr);
621  }
622  else
623  {
624  LOG_ERROR("Error reading current slew rate");
625  }
626 }
627 
628 
629 /*
630  * getBasicData: standard LX200 commands
631  */
633 {
634  int currentSiteIndex;
635 
636  if (!isSimulation())
637  {
639  char buffer[128];
641  IUSaveText(&VersionT[0], buffer);
643  IUSaveText(&VersionT[1], buffer);
645  statusCommand = ":GXI#";
646  guideSpeedCommand = ":SXR0:%02d#";
647  IUSaveText(&VersionT[2], buffer);
649  IUSaveText(&VersionT[3], buffer);
650 
651  IDSetText(&VersionTP, nullptr);
652  SiteNameT[0].text = new char[64];
653  sendScopeTime();
654 
655  if (getSiteIndex(&currentSiteIndex))
656  {
657  SiteS[currentSiteIndex].s = ISS_ON;
658  currentSiteNum = currentSiteIndex + 1;
659  LOGF_INFO("Site number %d", currentSiteNum);
660  getSiteName(PortFD, SiteNameTP.tp[0].text, currentSiteNum);
661  SiteNameTP.s = IPS_OK;
662  SiteSP.s = IPS_OK;
663  IDSetText(&SiteNameTP, nullptr);
664  IDSetSwitch(&SiteSP, nullptr);
665  getLocation(); // read site from TeenAstro
666  }
667  else
668  {
669  LOG_ERROR("Error reading current site number");
670  }
671 
672 
673  // Get initial state and set switches
674  for (unsigned i = 0; i < sizeof(OldOSStat); i++)
675  OldOSStat[i] = 'x'; // reset old OS stat to force re-evaluation
676  getCommandString(PortFD, OSStat, statusCommand); // returns a string containing controller status
677  handleStatusChange();
678  LOGF_INFO("Initial Status: %s", OSStat);
679 
680  updateSlewRate();
681  SetGuideRate(INITIAL_GUIDE_RATE);
682 
683  // Turn off tracking. (too much interaction with telescope.cpp if we try to keep the mount's current track state)
684  if (TrackState != SCOPE_TRACKING)
685  {
686  SetTrackEnabled(false);
687  }
688 
689 
690  if (InitPark())
691  {
692  // If loading parking data is successful, we just set the default parking values.
693  LOG_INFO("=============== Parkdata loaded");
694  }
695  else
696  {
697  // Otherwise, we set all parking data to default in case no parking data is found.
698  LOG_INFO("=============== Parkdata Load Failed");
699  }
700  }
701 }
702 
703 /*
704  * ISNewNumber: callback from user interface
705  *
706  * when user has entered a number, handle it to store corresponding driver parameter
707  *
708  */
709 bool LX200_TeenAstro::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
710 {
711  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
712  {
713  if (!strcmp(name, SlewAccuracyNP.name))
714  {
715  if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
716  return false;
717 
718  SlewAccuracyNP.s = IPS_OK;
719 
720  if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
721  IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
722 
723  IDSetNumber(&SlewAccuracyNP, nullptr);
724  return true;
725  }
726  if (!strcmp(name, GuideRateNP.name))
727  {
728  IUUpdateNumber(&GuideRateNP, values, names, n);
729  GuideRateNP.s = IPS_OK;
730  IDSetNumber(&GuideRateNP, nullptr);
731  float guideRate = GuideRateN[0].value;
732  SetGuideRate(guideRate);
733  }
734 
735  // GUIDE process Guider properties.
736  processGuiderProperties(name, values, names, n);
737  }
738 
739  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
740 }
741 
742 
743 
744 /*
745  * ISNewSwitch: callback from user interface
746  *
747  * when user has entered a switch, handle it to store corresponding driver parameter
748  *
749  */
750 bool LX200_TeenAstro::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
751 {
752 
753  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
754  {
755  // Slew button speed
756  if (!strcmp(name, SlewRateSP.name))
757  {
758  IUUpdateSwitch(&SlewRateSP, states, names, n);
759  int slewRate = IUFindOnSwitchIndex(&SlewRateSP);
760 
761  if (!selectSlewRate(slewRate))
762  {
763  LOGF_ERROR("Error setting move to rate %d.", slewRate);
764  return false;
765  }
766 
767  SlewRateSP.s = IPS_OK;
768  IDSetSwitch(&SlewRateSP, nullptr);
769  return true;
770  }
771 
772  // Sites
773  if (!strcmp(name, SiteSP.name))
774  {
775  if (IUUpdateSwitch(&SiteSP, states, names, n) < 0)
776  return false;
777 
778  currentSiteNum = IUFindOnSwitchIndex(&SiteSP) + 1;
779  LOGF_DEBUG("currentSiteNum: %d", currentSiteNum);
780  if (!isSimulation() && (!setSite(currentSiteNum)))
781  {
782  SiteSP.s = IPS_ALERT;
783  IDSetSwitch(&SiteSP, "Error selecting sites.");
784  return false;
785  }
786 
787  if (isSimulation())
788  IUSaveText(&SiteNameTP.tp[0], "Sample Site");
789  else
790  {
791  LOGF_DEBUG("Site name %s", SiteNameTP.tp[0].text);
792  getSiteName(PortFD, SiteNameTP.tp[0].text, currentSiteNum);
793  }
794 
795  // When user selects a new site, read it from TeenAstro
796  getLocation();
797 
798  LOGF_INFO("Setting site number %d", currentSiteNum);
799  SiteS[currentSiteNum - 1].s = ISS_ON;
800  SiteNameTP.s = IPS_OK;
801  SiteSP.s = IPS_OK;
802 
803  IDSetText(&SiteNameTP, nullptr);
804  IDSetSwitch(&SiteSP, nullptr);
805 
806  return false;
807  }
808  }
809 
810  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
811 }
812 
813 bool LX200_TeenAstro::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
814 {
815  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
816  {
817  if (!strcmp(name, SiteNameTP.name))
818  {
819  if (!isSimulation() && setSiteName(PortFD, texts[0], currentSiteNum) < 0)
820  {
821  SiteNameTP.s = IPS_ALERT;
822  IDSetText(&SiteNameTP, nullptr);
823  return false;
824  }
825 
826  SiteNameTP.s = IPS_OK;
827  IText *tp = IUFindText(&SiteNameTP, names[0]);
828  IUSaveText(tp, texts[0]);
829  IDSetText(&SiteNameTP, nullptr);
830  return true;
831  }
832  }
833 
834  return INDI::Telescope::ISNewText(dev, name, texts, names, n);
835 }
836 
837 
838 
839 /*
840  * getLocalDate() to sendScopeTime() are copied from lx200telescope.cpp
841  */
842 bool LX200_TeenAstro::getLocalDate(char *dateString)
843 {
844  if (isSimulation())
845  {
846  time_t now = time(nullptr);
847  strftime(dateString, MAXINDINAME, "%F", localtime(&now));
848  }
849  else
850  {
851  getCalendarDate(PortFD, dateString);
852  }
853 
854  return true;
855 }
856 
857 bool LX200_TeenAstro::setLocalDate(uint8_t days, uint8_t months, uint16_t years)
858 {
859  return (setCalenderDate(PortFD, days, months, years) == 0);
860 }
861 
862 bool LX200_TeenAstro::getLocalTime(char *timeString)
863 {
864  if (isSimulation())
865  {
866  time_t now = time(nullptr);
867  strftime(timeString, MAXINDINAME, "%T", localtime(&now));
868  }
869  else
870  {
871  double ctime = 0;
872  int h, m, s;
873  getLocalTime24(PortFD, &ctime);
874  getSexComponents(ctime, &h, &m, &s);
875  snprintf(timeString, MAXINDINAME, "%02d:%02d:%02d", h, m, s);
876  }
877 
878  return true;
879 }
880 
881 
882 bool LX200_TeenAstro::getUTFOffset(double *offset)
883 {
884  if (isSimulation())
885  {
886  *offset = 3;
887  return true;
888  }
889 
890  int lx200_utc_offset = 0;
891  getUTCOffset(PortFD, &lx200_utc_offset);
892 
893  // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
894  *offset = lx200_utc_offset * -1;
895  return true;
896 }
897 
898 bool LX200_TeenAstro::sendScopeTime()
899 {
900  char cdate[MAXINDINAME] = {0};
901  char ctime[MAXINDINAME] = {0};
902  struct tm ltm;
903  struct tm utm;
904  time_t time_epoch;
905 
906  memset(&ltm, 0, sizeof(ltm));
907  memset(&utm, 0, sizeof(utm));
908 
909  double offset = 0;
910 
911  if (getUTFOffset(&offset))
912  {
913  char utcStr[8] = {0};
914  snprintf(utcStr, sizeof(utcStr), "%.2f", offset);
915  IUSaveText(&TimeT[1], utcStr);
916  }
917  else
918  {
919  LOG_WARN("Could not obtain UTC offset from mount!");
920  return false;
921  }
922 
923  if (getLocalTime(ctime) == false)
924  {
925  LOG_WARN("Could not obtain local time from mount!");
926  return false;
927  }
928 
929  if (getLocalDate(cdate) == false)
930  {
931  LOG_WARN("Could not obtain local date from mount!");
932  return false;
933  }
934 
935  // To ISO 8601 format in LOCAL TIME!
936  char datetime[MAXINDINAME] = {0};
937  snprintf(datetime, MAXINDINAME, "%sT%s", cdate, ctime);
938 
939  // Now that date+time are combined, let's get tm representation of it.
940  if (strptime(datetime, "%FT%T", &ltm) == nullptr)
941  {
942  LOGF_WARN("Could not process mount date and time: %s", datetime);
943  return false;
944  }
945 
946  ltm.tm_isdst = 0;
947  // Get local time epoch in UNIX seconds
948  time_epoch = mktime(&ltm);
949 
950  // LOCAL to UTC by subtracting offset.
951  time_epoch -= static_cast<int>(offset * 3600.0);
952 
953  // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time)
954  localtime_r(&time_epoch, &utm);
955 
956  // Format it into the final UTC ISO 8601
957  strftime(cdate, MAXINDINAME, "%Y-%m-%dT%H:%M:%S", &utm);
958  IUSaveText(&TimeT[0], cdate);
959 
960  LOGF_DEBUG("Mount controller UTC Time: %s", TimeT[0].text);
961  LOGF_DEBUG("Mount controller UTC Offset: %s", TimeT[1].text);
962 
963  // Let's send everything to the client
964  TimeTP.s = IPS_OK;
965  IDSetText(&TimeTP, nullptr);
966 
967  return true;
968 }
969 /*
970  * Called by INDI - not sure when
971  */
972 
973 bool LX200_TeenAstro::sendScopeLocation()
974 {
975  int dd = 0, mm = 0, elev = 0;
976  double ssf = 0.0;
977 
978  LOG_INFO("Send location");
979  return true;
980 
981  if (isSimulation())
982  {
983  LocationNP.np[LOCATION_LATITUDE].value = 29.5; // Kuwait - Jasem's home!
984  LocationNP.np[LOCATION_LONGITUDE].value = 48.0;
985  LocationNP.np[LOCATION_ELEVATION].value = 10;
986  LocationNP.s = IPS_OK;
987  IDSetNumber(&LocationNP, nullptr);
988  return true;
989  }
990 
991  if (getSiteLatitude(PortFD, &dd, &mm, &ssf) < 0)
992  {
993  LOG_WARN("Failed to get site latitude from device.");
994  return false;
995  }
996  else
997  {
998  if (dd > 0)
999  LocationNP.np[LOCATION_LATITUDE].value = dd + mm / 60.0;
1000  else
1001  LocationNP.np[LOCATION_LATITUDE].value = dd - mm / 60.0;
1002  }
1003  if (getSiteLongitude(PortFD, &dd, &mm, &ssf) < 0)
1004  {
1005  LOG_WARN("Failed to get site longitude from device.");
1006  return false;
1007  }
1008  else
1009  {
1010  if (dd > 0)
1011  LocationNP.np[LOCATION_LONGITUDE].value = 360.0 - (dd + mm / 60.0);
1012  else
1013  LocationNP.np[LOCATION_LONGITUDE].value = (dd - mm / 60.0) * -1.0;
1014  }
1015  LOGF_DEBUG("Mount Controller Latitude: %g Longitude: %g", LocationN[LOCATION_LATITUDE].value,
1016  LocationN[LOCATION_LONGITUDE].value);
1017 
1018  if (getSiteElevation(&elev))
1019  {
1020  LocationNP.np[LOCATION_ELEVATION].value = elev;
1021  }
1022  else
1023  {
1024  LOG_ERROR("Error getting site elevation");
1025  }
1026  IDSetNumber(&LocationNP, nullptr);
1027  saveConfig(true, "GEOGRAPHIC_COORD");
1028 
1029  return true;
1030 }
1031 
1032 /*
1033  * getSiteElevation - not in Meade standard
1034  */
1035 bool LX200_TeenAstro::getSiteElevation(int *elevationP)
1036 {
1037  if (getCommandInt(PortFD, elevationP, ":Ge#") != 0)
1038  return false;
1039  return true;
1040 }
1041 
1042 /*
1043  * getSiteIndex - not in Meade standard
1044  */
1045 bool LX200_TeenAstro::getSiteIndex(int *ndxP)
1046 {
1047  if (getCommandInt(PortFD, ndxP, ":W?#") != 0)
1048  return false;
1049  return true;
1050 }
1051 
1052 
1053 /*
1054  * getSlewRate - not in Meade standard
1055  */
1056 bool LX200_TeenAstro::getSlewRate(int *ndxP)
1057 {
1058  unsigned char rate = (OSStat[4] - '0');
1059  *ndxP = (int) rate;
1060  return true;
1061 }
1062 
1063 /*
1064  * setSite - not in Meade standard
1065  * argument is the site number (1 to 4)
1066  * TeenAstro handles numbers 0 to 3
1067  */
1068 bool LX200_TeenAstro::setSite(int num)
1069 {
1070  char buf[10];
1071  snprintf (buf, sizeof(buf), ":W%d#", num - 1);
1072  sendCommand(buf);
1073  return true;
1074 }
1075 
1076 /*
1077  * setSiteElevation - not in Meade standard
1078  */
1079 bool LX200_TeenAstro::setSiteElevation(double elevation)
1080 {
1081  char buf[20];
1082  snprintf (buf, sizeof(buf), ":Se%+4d#", static_cast<int>(elevation));
1083  sendCommand(buf);
1084  return true;
1085 }
1086 
1087 
1088 /*
1089  * getLocation
1090  * retrieve from scope, set into user interface
1091  */
1092 bool LX200_TeenAstro::getLocation()
1093 {
1094  int dd = 0, mm = 0, elev = 0;
1095  double ssf = 0.0;
1096 
1097  if (getSiteLatitude(PortFD, &dd, &mm, &ssf) < 0)
1098  {
1099  LOG_WARN("Failed to get site latitude from device.");
1100  return false;
1101  }
1102  else
1103  {
1104  if (dd > 0)
1105  LocationNP.np[LOCATION_LATITUDE].value = dd + mm / 60.0;
1106  else
1107  LocationNP.np[LOCATION_LATITUDE].value = dd - mm / 60.0;
1108  }
1109 
1110  if (getSiteLongitude(PortFD, &dd, &mm, &ssf) < 0)
1111  {
1112  LOG_WARN("Failed to get site longitude from device.");
1113  return false;
1114  }
1115  else
1116  {
1117  if (dd > 0)
1118  LocationNP.np[LOCATION_LONGITUDE].value = 360.0 - (dd + mm / 60.0);
1119  else
1120  LocationNP.np[LOCATION_LONGITUDE].value = (dd - mm / 60.0) * -1.0;
1121  }
1122  if (getSiteElevation(&elev))
1123  {
1124  LocationNP.np[LOCATION_ELEVATION].value = elev;
1125  }
1126  else
1127  {
1128  LOG_ERROR("Error getting site elevation");
1129  }
1130 
1131  IDSetNumber(&LocationNP, nullptr);
1132  return true;
1133 }
1134 
1135 /*
1136  * Set Guide Rate - :SXR0:dddd# (v1.2 and above) where ddd is guide rate * 100
1137  */
1138 bool LX200_TeenAstro::SetGuideRate(float guideRate)
1139 {
1140  char cmdString[20];
1141 
1142  snprintf (cmdString, sizeof(cmdString), guideSpeedCommand, (int) (guideRate * 100));
1143  sendCommand(cmdString);
1144 
1145  return true;
1146 }
1147 
1148 
1149 /*
1150  * Guidexxx - use SendPulseCmd function from lx200driver.cpp
1151  */
1153 {
1155  return IPS_OK;
1156 }
1157 
1159 {
1161  return IPS_OK;
1162 }
1163 
1165 {
1166  SendPulseCmd(LX200_EAST, ms);
1167  return IPS_OK;
1168 }
1169 
1171 {
1172  SendPulseCmd(LX200_WEST, ms);
1173  return IPS_OK;
1174 }
1175 
1176 void LX200_TeenAstro::SendPulseCmd(int8_t direction, uint32_t duration_msec)
1177 {
1178  ::SendPulseCmd(PortFD, direction, duration_msec);
1179 }
1180 
1181 
1182 /*
1183  * Abort() calls standard lx200driver command (:Q#)
1184  */
1186 {
1187  if (!isSimulation() && abortSlew(PortFD) < 0)
1188  {
1189  LOG_ERROR("Failed to abort slew.");
1190  return false;
1191  }
1192 
1193  EqNP.s = IPS_IDLE;
1195  IDSetNumber(&EqNP, nullptr);
1196 
1197  LOG_INFO("Slew aborted.");
1198  return true;
1199 }
1200 
1201 /*
1202  * MoveNS and MoveWE call lx200telescope functions
1203  */
1205 {
1206  if (dirns == DIRECTION_NORTH)
1207  return Move(LX200_NORTH, cmd);
1208  else
1209  return Move(LX200_SOUTH, cmd);
1210 }
1212 {
1213  if (dirwe == DIRECTION_WEST)
1214  return Move(LX200_WEST, cmd);
1215  else
1216  return Move(LX200_EAST, cmd);
1217 }
1218 
1219 /*
1220  * Single function for move - use LX200 functions
1221  */
1222 bool LX200_TeenAstro::Move(TDirection dir, TelescopeMotionCommand cmd)
1223 {
1224  switch (cmd)
1225  {
1226  case MOTION_START:
1227  MoveTo(PortFD, dir);
1228  break;
1229  case MOTION_STOP:
1230  HaltMovement(PortFD, dir);
1231  break;
1232  }
1233  return true;
1234 }
1235 
1236 /*
1237  * Override default config saving
1238  */
1240 {
1241  IUSaveConfigSwitch(fp, &SlewRateSP);
1242  IUSaveConfigNumber(fp, &GuideRateNP);
1243 
1245 }
1246 
1247 
1248 /*
1249  * Mount simulation
1250  */
1251 void LX200_TeenAstro::mountSim()
1252 {
1253  static struct timeval ltv;
1254  struct timeval tv;
1255  double dt, da, dx;
1256  int nlocked;
1257 
1258  /* update elapsed time since last poll, don't presume exactly POLLMS */
1259  gettimeofday(&tv, nullptr);
1260 
1261  if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1262  ltv = tv;
1263 
1264  dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1265  ltv = tv;
1266  da = SLEWRATE * dt;
1267 
1268  /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
1269  switch (TrackState)
1270  {
1271  case SCOPE_TRACKING:
1272  /* RA moves at sidereal, Dec stands still */
1273  currentRA += (SIDRATE * dt / 15.);
1274  break;
1275 
1276  case SCOPE_SLEWING:
1277  /* slewing - nail it when both within one pulse @ SLEWRATE */
1278  nlocked = 0;
1279 
1280  dx = targetRA - currentRA;
1281 
1282  if (fabs(dx) <= da)
1283  {
1284  currentRA = targetRA;
1285  nlocked++;
1286  }
1287  else if (dx > 0)
1288  currentRA += da / 15.;
1289  else
1290  currentRA -= da / 15.;
1291 
1292  dx = targetDEC - currentDEC;
1293  if (fabs(dx) <= da)
1294  {
1295  currentDEC = targetDEC;
1296  nlocked++;
1297  }
1298  else if (dx > 0)
1299  currentDEC += da;
1300  else
1301  currentDEC -= da;
1302 
1303  if (nlocked == 2)
1304  {
1306  }
1307 
1308  break;
1309 
1310  default:
1311  break;
1312  }
1313 
1315 }
1316 
1317 void LX200_TeenAstro::slewError(int slewCode)
1318 {
1319  EqNP.s = IPS_ALERT;
1320 
1321  if (slewCode == 1)
1322  IDSetNumber(&EqNP, "Object below horizon.");
1323  else if (slewCode == 2)
1324  IDSetNumber(&EqNP, "Object below the minimum elevation limit.");
1325  else
1326  IDSetNumber(&EqNP, "Slew failed.");
1327 }
1328 /*
1329  * Enable or disable sidereal tracking (events handled by inditelescope)
1330  */
1332 {
1333  LOGF_INFO("TrackEnable %d", enabled);
1334 
1335  if (enabled)
1336  {
1337  sendCommand(":Te#");
1338  }
1339  else
1340  {
1341  sendCommand(":Td#");
1342  }
1343  return true;
1344 }
1345 
1346 /*
1347  * selectSlewrate - select among TeenAstro's 5 predefined rates
1348  */
1349 bool LX200_TeenAstro::selectSlewRate(int index)
1350 {
1351  char cmd[20];
1352 
1353  snprintf(cmd, sizeof(cmd), ":R%d#", index);
1354  sendCommand(cmd);
1355  return true;
1356 }
1357 
1358 
1359 /*
1360  * Used instead of getCommandString when response is not terminated with '#'
1361  *
1362  */
1363 void LX200_TeenAstro::sendCommand(const char *cmd)
1364 {
1365  char resp;
1366  int nbytes_read;
1367  std::unique_lock<std::mutex> guard(lx200CommsLock);
1368  LOGF_INFO("sendCommand %s", cmd);
1369  int rc = write(PortFD, cmd, strlen(cmd));
1370  rc = tty_read(PortFD, &resp, 1, ONSTEP_TIMEOUT, &nbytes_read);
1371  INDI_UNUSED(rc);
1372 }
1373 
1374 
1375 
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 setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
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
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
uint16_t getDriverInterface() const
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
ISwitchVectorProperty ParkOptionSP
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
INumberVectorProperty LocationNP
virtual bool initProperties() override
Called to initialize basic properties required all the time.
ITextVectorProperty TimeTP
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
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 int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
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.
ISwitchVectorProperty ParkSP
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
INumber LocationN[3]
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
ISwitchVectorProperty MovementWESP
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.
virtual const char * getDriverName() override
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
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 ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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 Handshake() override
perform handshake with device to check communication
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual const char * getDefaultName() override
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool Park() override
Park the telescope to its home position.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void getBasicData()
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
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.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
#define currentDEC
Definition: ieq45.cpp:48
#define currentRA
Definition: ieq45.cpp:47
double ra
double dec
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition: indiapi.h:500
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ 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
#define MAXINDINAME
Definition: indiapi.h:191
INDI_DIR_WE
Definition: indibasetypes.h:55
@ DIRECTION_WEST
Definition: indibasetypes.h:56
INDI_DIR_NS
Definition: indibasetypes.h:48
@ DIRECTION_NORTH
Definition: indibasetypes.h:49
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:254
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
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
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 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 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
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indidevapi.c:56
#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 LOGF_WARN(fmt,...)
Definition: indilogger.h:81
#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 RB_MAX_LEN
Definition: lx200_OnStep.h:147
std::mutex lx200CommsLock
Definition: lx200driver.cpp:56
#define SIDRATE
#define FIRMWARE_TAB
#define SLEWRATE
#define ONSTEP_TIMEOUT
#define INITIAL_GUIDE_RATE
int SendPulseCmd(int fd, int direction, int duration_msec, bool wait_after_command, int max_wait_ms)
int getSiteLongitude(int fd, int *ddd, int *mm, double *ssf)
int selectTrackingMode(int fd, int trackMode)
int getSiteName(int fd, char *siteName, int siteNum)
int getCommandInt(int fd, int *value, const char *cmd)
int setObjectRA(int fd, double ra, bool addSpace)
int setObjectDEC(int fd, double dec, bool addSpace)
int checkLX200EquatorialFormat(int fd)
int abortSlew(int fd)
int setCalenderDate(int fd, int dd, int mm, int yy, bool addSpace)
int getCalendarDate(int fd, char *date)
int Slew(int fd)
int MoveTo(int fd, int direction)
int setSiteName(int fd, char *siteName, int siteNum)
void setLX200Debug(const char *deviceName, unsigned int debug_level)
Definition: lx200driver.cpp:58
int HaltMovement(int fd, int direction)
int getCommandString(int fd, char *data, const char *cmd)
int getSiteLatitude(int fd, int *dd, int *mm, double *ssf)
#define getUTCOffset(fd, x)
Definition: lx200driver.h:137
#define getVersionDate(fd, x)
Definition: lx200driver.h:129
#define getVersionTime(fd, x)
Definition: lx200driver.h:130
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
#define getVersionNumber(fd, x)
Definition: lx200driver.h:132
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
TDirection
Definition: lx200driver.h:40
@ LX200_WEST
Definition: lx200driver.h:42
@ LX200_SOUTH
Definition: lx200driver.h:44
@ LX200_NORTH
Definition: lx200driver.h:41
@ LX200_EAST
Definition: lx200driver.h:43
#define getProductName(fd, x)
Definition: lx200driver.h:133
#define getLocalTime24(fd, x)
Definition: lx200driver.h:122
#define slewToPark(fd)
Definition: lx200driver.h:174
std::vector< uint8_t > buffer
bool setSite(const int fd, const double longitude, const double latitude)
__u8 cmd[4]
Definition: pwc-ioctl.h:2
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
One text descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250