Instrument Neutral Distributed Interface INDI 2.2.5
lx200_TeenAstro.cpp
Go to the documentation of this file.
1/*
2
3LX200_TeenAstro
4
5Based on LX200_OnStep and others
6François Desvallées https://github.com/fdesvallees
7
8Copyright (C) 2015 Jasem Mutlaq ([email protected])
9
10This library is free software;
11you can redistribute it and / or
12modify it under the terms of the GNU Lesser General Public
13License as published by the Free Software Foundation;
14either
15version 2.1 of the License, or (at your option) any later version.
16
17This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY;
19without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21Lesser General Public License for more details.
22
23You should have received a copy of the GNU Lesser General Public
24License along with this library;
25if not, write to the Free Software
26Foundation, 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
53static std::unique_ptr<LX200_TeenAstro> teenAstro(new LX200_TeenAstro());
54extern std::mutex lx200CommsLock;
55
56/*
57 * LX200 TeenAstro constructor
58 */
60{
61 setVersion(1, 4); // 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",
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", "",
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
153
154 return true;
155}
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 // Firmware Data
192 defineProperty(&VersionTP);
193 getBasicData();
194 }
195 else
196 {
197 // Main Control
198 deleteProperty(SlewAccuracyNP.name);
199 deleteProperty(ErrorStatusTP.name);
200 // Connection
201 // Options
202 // Motion Control
203 deleteProperty(SlewRateSP.name);
204 deleteProperty(GuideRateNP.name);
205 deleteProperty(SiteSP.name);
206 deleteProperty(SiteNameTP.name);
207
208 // Site Management
210 deleteProperty(SetHomeSP.name);
211 // Firmware Data
212 deleteProperty(VersionTP.name);
213 }
214
216
217 return true;
218}
219
220
222{
223 if (isSimulation())
224 {
225 LOG_INFO("Simulated Connection.");
226 return true;
227 }
228
229 if (getLX200RA(PortFD, &currentRA) != 0)
230 {
231 LOG_ERROR("Error communicating with telescope.");
232 return false;
233 }
234 LOG_INFO("TeenAstro is Connected");
235 return true;
236}
237
238/*
239 * ReadScopeStatus
240 * Called when polling the mount about once per second
241 */
243{
244 if (isSimulation())
245 {
246 mountSim();
247 return true;
248 }
249 if (!isConnected())
250 return false;
251
252 if (getLX200RA(PortFD, &currentRA) < 0 || getLX200DEC(PortFD, &currentDEC) < 0)
253 {
255 return false;
256 }
257
259 {
260 // Check if LX200 is done slewing
261 if (isSlewComplete())
262 {
264 LOG_INFO("Slew is complete. Tracking...");
265 }
266 }
267 else if (TrackState == SCOPE_PARKING)
268 {
269 LOG_INFO("Parking");
270 }
271
272 // update mount status
273 getCommandString(PortFD, OSStat, statusCommand); // returns a string containing controller status
274 if (OSStat[15] != '0')
275 {
276 updateMountStatus(OSStat[15]); // error
277 }
278 if (strcmp(OSStat, OldOSStat) != 0) // if status changed
279 {
280 handleStatusChange();
281 snprintf(OldOSStat, sizeof(OldOSStat), "%s", OSStat);
282 }
283#if 0
284 // HACK: simulate small change in RA to force update of hour angle (EKOS bug)
285 static bool incRa;
286 if (incRa)
287 {
288 currentRA += 0.000001; // 0.02 arc sec
289 incRa = false;
290 }
291 else
292 {
293 incRa = true;
294 }
295#endif
296
297 NewRaDec(currentRA, currentDEC);
298
299 return true;
300}
301
302/*
303 * Use OSStat to detect status change - handle each byte separately
304 * called by ReadScopeStatus()
305 */
306void LX200_TeenAstro::handleStatusChange(void)
307{
308 LOGF_DEBUG ("Status Change: %s", OSStat);
309
310 if (OSStat[0] != OldOSStat[0])
311 {
312 if (OSStat[0] == '0')
313 {
315 }
316 else if (OSStat[0] == '1')
317 {
319 }
320 else if (OSStat[0] == '2' || OSStat[0] == '3' )
321 {
323 }
324 }
325
326
327 // Byte 2 is park status
328 if (OSStat[2] != OldOSStat[2])
329 {
330 if (OSStat[2] == 'P')
331 {
332 SetParked(true); // defaults to TrackState=SCOPE_PARKED
333 }
334 else
335 {
336 SetParked(false);
337 // SetTrackEnabled(false); //disable since TeenAstro enables it by default
338 }
339 }
340 // Byte 4 is current slew rate
341 if (OSStat[4] != OldOSStat[4])
342 {
343 updateSlewRate();
344 }
345
346
347 // Byte 13 is pier side
348 if (OSStat[13] != OldOSStat[13])
349 {
351 }
352 // Byte 15 is the error status
353 if (OSStat[15] != OldOSStat[15])
354 {
355 updateMountStatus(OSStat[15]);
356 }
357}
358
359/*
360 * Mount Error status
361 * 0:ERR_NONE, 1: ERR_MOTOR_FAULT, 2: ERR_ALT, 3: ERR_LIMIT_SENSE
362 * 4: ERR_AXIS2,5: ERR_AZM, 6: ERR_UNDER_POLE, 7: ERR_MERIDIAN, 8: ERR_SYNC
363 */
364void LX200_TeenAstro::updateMountStatus(char status)
365{
366 static const char *errCodes[9] = {"ERR_NONE", "ERR_MOTOR_FAULT", "ERR_ALT", "ERR_LIMIT_SENSE",
367 "ERR_AXIS2", "ERR_AZM", "ERR_UNDER_POLE", "ERR_MERIDIAN", "ERR_SYNC"
368 };
369
370 if (status < '0' || status > '9')
371 {
372 return;
373 }
374 if (status == '0')
375 {
376 ErrorStatusTP.s = IPS_OK;
377 }
378 else
379 {
380 ErrorStatusTP.s = IPS_ALERT;
381 TrackState = SCOPE_IDLE; // Tell Ekos mount is not tracking anymore
382 }
383 IUSaveText(&ErrorStatusT[0], errCodes[status - '0']);
384 IDSetText(&ErrorStatusTP, nullptr);
385}
386
387/*
388 * Goto target
389 * Use standard lx200driver command (:Sr #)
390 * Set state to slewing
391 */
392bool LX200_TeenAstro::Goto(double r, double d)
393{
394 targetRA = r;
395 targetDEC = d;
396 char RAStr[64] = {0}, DecStr[64] = {0};
397
398 fs_sexa(RAStr, targetRA, 2, 3600);
399 fs_sexa(DecStr, targetDEC, 2, 3600);
400
401 // If moving, let's stop it first.
402 if (EqNP.getState() == IPS_BUSY)
403 {
404 if (!isSimulation() && abortSlew(PortFD) < 0)
405 {
407 LOG_ERROR("Abort slew failed.");
408 AbortSP.apply();
409 return false;
410 }
411
414 LOG_ERROR("Slew aborted.");
415 AbortSP.apply();
416 EqNP.apply();
417
418 // sleep for 100 mseconds
419 const struct timespec ms100_delay = {.tv_sec = 0, .tv_nsec = 100000000};
420 nanosleep(&ms100_delay, NULL);
421 }
422
423 if (!isSimulation())
424 {
425 if (setObjectRA(PortFD, targetRA) < 0 || (setObjectDEC(PortFD, targetDEC)) < 0) // standard LX200 command
426 {
428 LOG_ERROR("Error setting RA/DEC.");
429 EqNP.apply();
430 return false;
431 }
432
433 int err = 0;
434
435 /* Slew reads the '0', that is not the end of the slew */
436 if ((err = Slew(PortFD)))
437 {
439 LOGF_ERROR("Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
440 EqNP.apply();
441 slewError(err);
442 return false;
443 }
444 }
445
448
449 LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
450 return true;
451}
452
453bool 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 */
473bool 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 {
481 LOG_ERROR("Error setting RA/DEC. Unable to Sync.");
482 EqNP.apply();
483 return false;
484 }
485
486 // Use the parent Sync() function (lx200driver.cpp)
487 if (!isSimulation() && ::Sync(PortFD, syncString) < 0)
488 {
490 LOG_ERROR("Synchronization failed");
491 EqNP.apply();
492 return false;
493 }
494
495 currentRA = ra;
496 currentDEC = dec;
497
498 LOG_INFO("Synchronization successful.");
501
502 return true;
503}
504
505
506
507//======================== Parking =======================
509{
510 char response[RB_MAX_LEN];
511
512 if (isSimulation())
513 {
514 LOG_DEBUG("SetCurrentPark: CMD <:hQ>");
515 return true;
516 }
517
518 if (getCommandString(PortFD, response, ":hQ#") < 0)
519 {
520 LOGF_WARN("===CMD==> Set Park Pos %s", response);
521 return false;
522 }
525 LOG_WARN("Park Value set to current position");
526 return true;
527}
528
530{
531 char response[RB_MAX_LEN];
532
533 if (isSimulation())
534 {
535 LOG_DEBUG("UnPark: CMD <:hR>");
538 return true;
539 }
540 if (getCommandString(PortFD, response, ":hR#") < 0)
541 {
542 return false;
543 }
544 SetParked(false);
545
546 return true;
547}
548
550{
551 if (isSimulation())
552 {
553 LOG_DEBUG("SlewToPark: CMD <:hP>");
556 return true;
557 }
558
559 // If scope is moving, let's stop it first.
560 if (EqNP.getState() == IPS_BUSY)
561 {
562 if (abortSlew(PortFD) < 0)
563 {
564 Telescope::AbortSP.setState(IPS_ALERT);
565 LOG_ERROR("Abort slew failed.");
566 Telescope::AbortSP.apply();
567 return false;
568 }
569 Telescope::AbortSP.setState(IPS_OK);
571 LOG_ERROR("Slew aborted.");
572 Telescope::AbortSP.apply();
573 EqNP.apply();
574
576 {
582
585 }
586 }
587 if (slewToPark(PortFD) < 0) // slewToPark is a macro (lx200driver.h)
588 {
590 LOG_ERROR("Parking Failed.");
591 ParkSP.apply();
592 return false;
593 }
596 LOG_INFO("Parking is in progress...");
597
598 return true;
599}
600
601
602/*
603 * updateLocation: not used - use hand controller to update
604 */
605bool LX200_TeenAstro::updateLocation(double latitude, double longitude, double elevation)
606{
607 INDI_UNUSED(latitude);
608 INDI_UNUSED(longitude);
609 INDI_UNUSED(elevation);
610
611 return true;
612}
613
614void LX200_TeenAstro::updateSlewRate()
615{
616 int slewRateIndex;
617
618 // get current slew rate
619 if (getSlewRate(&slewRateIndex))
620 {
621 LOGF_INFO("current slew rate : %d", slewRateIndex);
622 IUResetSwitch(&SlewRateSP);
623 SlewRateS[slewRateIndex].s = ISS_ON;
624 SlewRateSP.s = IPS_OK;
625 IDSetSwitch(&SlewRateSP, nullptr);
626 }
627 else
628 {
629 LOG_ERROR("Error reading current slew rate");
630 }
631}
632
633
634/*
635 * getBasicData: standard LX200 commands
636 */
638{
639 int currentSiteIndex;
640
641 if (!isSimulation())
642 {
644 char buffer[128];
645 getVersionDate(PortFD, buffer);
646 IUSaveText(&VersionT[0], buffer);
647 getVersionTime(PortFD, buffer);
648 IUSaveText(&VersionT[1], buffer);
649 getVersionNumber(PortFD, buffer);
650 statusCommand = ":GXI#";
651 guideSpeedCommand = ":SXR0:%02d#";
652 IUSaveText(&VersionT[2], buffer);
653 getProductName(PortFD, buffer);
654 IUSaveText(&VersionT[3], buffer);
655
656 IDSetText(&VersionTP, nullptr);
657 SiteNameT[0].text = new char[64];
658 sendScopeTime();
659
660 if (getSiteIndex(&currentSiteIndex))
661 {
662 SiteS[currentSiteIndex].s = ISS_ON;
663 currentSiteNum = currentSiteIndex + 1;
664 LOGF_INFO("Site number %d", currentSiteNum);
665 getSiteName(PortFD, SiteNameTP.tp[0].text, currentSiteNum);
666 SiteNameTP.s = IPS_OK;
667 SiteSP.s = IPS_OK;
668 IDSetText(&SiteNameTP, nullptr);
669 IDSetSwitch(&SiteSP, nullptr);
670 getLocation(); // read site from TeenAstro
671 }
672 else
673 {
674 LOG_ERROR("Error reading current site number");
675 }
676
677
678 // Get initial state and set switches
679 for (unsigned i = 0; i < sizeof(OldOSStat); i++)
680 OldOSStat[i] = 'x'; // reset old OS stat to force re-evaluation
681 getCommandString(PortFD, OSStat, statusCommand); // returns a string containing controller status
682 handleStatusChange();
683 LOGF_INFO("Initial Status: %s", OSStat);
684
685 updateSlewRate();
686 SetGuideRate(INITIAL_GUIDE_RATE);
687
688 // Turn off tracking. (too much interaction with telescope.cpp if we try to keep the mount's current track state)
690 {
691 SetTrackEnabled(false);
692 }
693
694
695 if (InitPark())
696 {
697 // If loading parking data is successful, we just set the default parking values.
698 LOG_INFO("=============== Parkdata loaded");
699 }
700 else
701 {
702 // Otherwise, we set all parking data to default in case no parking data is found.
703 LOG_INFO("=============== Parkdata Load Failed");
704 }
705 }
706}
707
708/*
709 * ISNewNumber: callback from user interface
710 *
711 * when user has entered a number, handle it to store corresponding driver parameter
712 *
713 */
714bool LX200_TeenAstro::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
715{
716 // Check guider interface
717 if (GI::processNumber(dev, name, values, names, n))
718 return true;
719
720 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
721 {
722 if (!strcmp(name, SlewAccuracyNP.name))
723 {
724 if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
725 return false;
726
727 SlewAccuracyNP.s = IPS_OK;
728
729 if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
730 IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
731
732 IDSetNumber(&SlewAccuracyNP, nullptr);
733 return true;
734 }
735 if (!strcmp(name, GuideRateNP.name))
736 {
737 IUUpdateNumber(&GuideRateNP, values, names, n);
738 GuideRateNP.s = IPS_OK;
739 IDSetNumber(&GuideRateNP, nullptr);
740 float guideRate = GuideRateN[0].value;
741 SetGuideRate(guideRate);
742 }
743 }
744
745 return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
746}
747
748/*
749 * ISNewSwitch: callback from user interface
750 *
751 * when user has entered a switch, handle it to store corresponding driver parameter
752 *
753 */
754bool LX200_TeenAstro::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
755{
756 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
757 {
758 // Slew button speed
759 if (!strcmp(name, SlewRateSP.name))
760 {
761 IUUpdateSwitch(&SlewRateSP, states, names, n);
762 int slewRate = IUFindOnSwitchIndex(&SlewRateSP);
763
764 if (!selectSlewRate(slewRate))
765 {
766 LOGF_ERROR("Error setting move to rate %d.", slewRate);
767 return false;
768 }
769
770 SlewRateSP.s = IPS_OK;
771 IDSetSwitch(&SlewRateSP, nullptr);
772 return true;
773 }
774
775 // Sites
776 if (!strcmp(name, SiteSP.name))
777 {
778 if (IUUpdateSwitch(&SiteSP, states, names, n) < 0)
779 return false;
780
781 currentSiteNum = IUFindOnSwitchIndex(&SiteSP) + 1;
782 LOGF_DEBUG("currentSiteNum: %d", currentSiteNum);
783 if (!isSimulation() && (!setSite(currentSiteNum)))
784 {
785 SiteSP.s = IPS_ALERT;
786 IDSetSwitch(&SiteSP, "Error selecting sites.");
787 return false;
788 }
789
790 if (isSimulation())
791 IUSaveText(&SiteNameTP.tp[0], "Sample Site");
792 else
793 {
794 LOGF_DEBUG("Site name %s", SiteNameTP.tp[0].text);
795 getSiteName(PortFD, SiteNameTP.tp[0].text, currentSiteNum);
796 }
797
798 // When user selects a new site, read it from TeenAstro
799 getLocation();
800
801 LOGF_INFO("Setting site number %d", currentSiteNum);
802 SiteS[currentSiteNum - 1].s = ISS_ON;
803 SiteNameTP.s = IPS_OK;
804 SiteSP.s = IPS_OK;
805
806 IDSetText(&SiteNameTP, nullptr);
807 IDSetSwitch(&SiteSP, nullptr);
808
809 return false;
810 }
811 }
812
813 return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
814}
815
816bool LX200_TeenAstro::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
817{
818 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
819 {
820 if (!strcmp(name, SiteNameTP.name))
821 {
822 if (!isSimulation() && setSiteName(PortFD, texts[0], currentSiteNum) < 0)
823 {
824 SiteNameTP.s = IPS_ALERT;
825 IDSetText(&SiteNameTP, nullptr);
826 return false;
827 }
828
829 SiteNameTP.s = IPS_OK;
830 IText *tp = IUFindText(&SiteNameTP, names[0]);
831 IUSaveText(tp, texts[0]);
832 IDSetText(&SiteNameTP, nullptr);
833 return true;
834 }
835 }
836
837 return INDI::Telescope::ISNewText(dev, name, texts, names, n);
838}
839
840
841
842/*
843 * getLocalDate() to sendScopeTime() are copied from lx200telescope.cpp
844 */
845bool LX200_TeenAstro::getLocalDate(char *dateString)
846{
847 if (isSimulation())
848 {
849 time_t now = time(nullptr);
850 strftime(dateString, MAXINDINAME, "%F", localtime(&now));
851 }
852 else
853 {
854 getCalendarDate(PortFD, dateString);
855 }
856
857 return true;
858}
859
860bool LX200_TeenAstro::setLocalDate(uint8_t days, uint8_t months, uint16_t years)
861{
862 return (setCalenderDate(PortFD, days, months, years) == 0);
863}
864
865bool LX200_TeenAstro::getLocalTime(char *timeString)
866{
867 if (isSimulation())
868 {
869 time_t now = time(nullptr);
870 strftime(timeString, MAXINDINAME, "%T", localtime(&now));
871 }
872 else
873 {
874 double ctime = 0;
875 int h, m, s;
876 getLocalTime24(PortFD, &ctime);
877 getSexComponents(ctime, &h, &m, &s);
878 snprintf(timeString, MAXINDINAME, "%02d:%02d:%02d", h, m, s);
879 }
880
881 return true;
882}
883
884
885bool LX200_TeenAstro::getUTFOffset(double *offset)
886{
887 if (isSimulation())
888 {
889 *offset = 3;
890 return true;
891 }
892
893 int lx200_utc_offset = 0;
894 getUTCOffset(PortFD, &lx200_utc_offset);
895
896 // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
897 *offset = lx200_utc_offset * -1;
898 return true;
899}
900
901bool LX200_TeenAstro::sendScopeTime()
902{
903 char cdate[MAXINDINAME] = {0};
904 char ctime[MAXINDINAME] = {0};
905 struct tm ltm;
906 struct tm utm;
907 time_t time_epoch;
908
909 memset(&ltm, 0, sizeof(ltm));
910 memset(&utm, 0, sizeof(utm));
911
912 double offset = 0;
913
914 if (getUTFOffset(&offset))
915 {
916 char utcStr[8] = {0};
917 snprintf(utcStr, sizeof(utcStr), "%.2f", offset);
918 TimeTP[OFFSET].setText(utcStr);
919 }
920 else
921 {
922 LOG_WARN("Could not obtain UTC offset from mount!");
923 return false;
924 }
925
926 if (getLocalTime(ctime) == false)
927 {
928 LOG_WARN("Could not obtain local time from mount!");
929 return false;
930 }
931
932 if (getLocalDate(cdate) == false)
933 {
934 LOG_WARN("Could not obtain local date from mount!");
935 return false;
936 }
937
938 // To ISO 8601 format in LOCAL TIME!
939 char datetime[MAXINDINAME] = {0};
940 snprintf(datetime, MAXINDINAME, "%sT%s", cdate, ctime);
941
942 // Now that date+time are combined, let's get tm representation of it.
943 if (strptime(datetime, "%FT%T", &ltm) == nullptr)
944 {
945 LOGF_WARN("Could not process mount date and time: %s", datetime);
946 return false;
947 }
948
949 ltm.tm_isdst = 0;
950 // Get local time epoch in UNIX seconds
951 time_epoch = mktime(&ltm);
952
953 // LOCAL to UTC by subtracting offset.
954 time_epoch -= static_cast<int>(offset * 3600.0);
955
956 // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time)
957 localtime_r(&time_epoch, &utm);
958
959 // Format it into the final UTC ISO 8601
960 strftime(cdate, MAXINDINAME, "%Y-%m-%dT%H:%M:%S", &utm);
961 TimeTP[UTC].setText(cdate);
962
963 LOGF_DEBUG("Mount controller UTC Time: %s", TimeTP[UTC].getText());
964 LOGF_DEBUG("Mount controller UTC Offset: %s", TimeTP[OFFSET].getText());
965
966 // Let's send everything to the client
968 TimeTP.apply();
969
970 return true;
971}
972/*
973 * Called by INDI - not sure when
974 */
975
976bool LX200_TeenAstro::sendScopeLocation()
977{
978 int dd = 0, mm = 0, elev = 0;
979 double ssf = 0.0;
980
981 LOG_INFO("Send location");
982 return true;
983
984 if (isSimulation())
985 {
986 LocationNP[LOCATION_LATITUDE].setValue(9.5); // Kuwait - Jasem's home!
987 LocationNP[LOCATION_LONGITUDE].setValue(48.0);
988 LocationNP[LOCATION_ELEVATION].setValue(10);
991 return true;
992 }
993
994 if (getSiteLatitude(PortFD, &dd, &mm, &ssf) < 0)
995 {
996 LOG_WARN("Failed to get site latitude from device.");
997 return false;
998 }
999 else
1000 {
1001 if (dd > 0)
1002 LocationNP[LOCATION_LATITUDE].setValue(dd + mm / 60.0);
1003 else
1004 LocationNP[LOCATION_LATITUDE].setValue(dd - mm / 60.0);
1005 }
1006 if (getSiteLongitude(PortFD, &dd, &mm, &ssf) < 0)
1007 {
1008 LOG_WARN("Failed to get site longitude from device.");
1009 return false;
1010 }
1011 else
1012 {
1013 if (dd > 0)
1014 LocationNP[LOCATION_LONGITUDE].setValue(360.0 - (dd + mm / 60.0));
1015 else
1016 LocationNP[LOCATION_LONGITUDE].setValue((dd - mm / 60.0) * -1.0);
1017 }
1018 LOGF_DEBUG("Mount Controller Latitude: %g Longitude: %g", LocationNP[LOCATION_LATITUDE].getValue(),
1019 LocationNP[LOCATION_LONGITUDE].getValue());
1020
1021 if (getSiteElevation(&elev))
1022 {
1023 LocationNP[LOCATION_ELEVATION].setValue(elev);
1024 }
1025 else
1026 {
1027 LOG_ERROR("Error getting site elevation");
1028 }
1029 LocationNP.apply();
1030 saveConfig(true, "GEOGRAPHIC_COORD");
1031
1032 return true;
1033}
1034
1035/*
1036 * getSiteElevation - not in Meade standard
1037 */
1038bool LX200_TeenAstro::getSiteElevation(int *elevationP)
1039{
1040 if (getCommandInt(PortFD, elevationP, ":Ge#") != 0)
1041 return false;
1042 return true;
1043}
1044
1045/*
1046 * getSiteIndex - not in Meade standard
1047 */
1048bool LX200_TeenAstro::getSiteIndex(int *ndxP)
1049{
1050 if (getCommandInt(PortFD, ndxP, ":W?#") != 0)
1051 return false;
1052 return true;
1053}
1054
1055
1056/*
1057 * getSlewRate - not in Meade standard
1058 */
1059bool LX200_TeenAstro::getSlewRate(int *ndxP)
1060{
1061 unsigned char rate = (OSStat[4] - '0');
1062 *ndxP = (int) rate;
1063 return true;
1064}
1065
1066/*
1067 * setSite - not in Meade standard
1068 * argument is the site number (1 to 4)
1069 * TeenAstro handles numbers 0 to 3
1070 */
1071bool LX200_TeenAstro::setSite(int num)
1072{
1073 char buf[10];
1074 snprintf (buf, sizeof(buf), ":W%d#", num - 1);
1075 sendCommand(buf);
1076 return true;
1077}
1078
1079/*
1080 * setSiteElevation - not in Meade standard
1081 */
1082bool LX200_TeenAstro::setSiteElevation(double elevation)
1083{
1084 char buf[20];
1085 snprintf (buf, sizeof(buf), ":Se%+4d#", static_cast<int>(elevation));
1086 sendCommand(buf);
1087 return true;
1088}
1089
1090
1091/*
1092 * getLocation
1093 * retrieve from scope, set into user interface
1094 */
1095bool LX200_TeenAstro::getLocation()
1096{
1097 int dd = 0, mm = 0, elev = 0;
1098 double ssf = 0.0;
1099
1100 if (getSiteLatitude(PortFD, &dd, &mm, &ssf) < 0)
1101 {
1102 LOG_WARN("Failed to get site latitude from device.");
1103 return false;
1104 }
1105 else
1106 {
1107 if (dd > 0)
1108 LocationNP[LOCATION_LATITUDE].setValue(dd + mm / 60.0);
1109 else
1110 LocationNP[LOCATION_LATITUDE].setValue(dd - mm / 60.0);
1111 }
1112
1113 if (getSiteLongitude(PortFD, &dd, &mm, &ssf) < 0)
1114 {
1115 LOG_WARN("Failed to get site longitude from device.");
1116 return false;
1117 }
1118 else
1119 {
1120 if (dd > 0)
1121 LocationNP[LOCATION_LONGITUDE].setValue(360.0 - (dd + mm / 60.0));
1122 else
1123 LocationNP[LOCATION_LONGITUDE].setValue((dd - mm / 60.0) * -1.0);
1124 }
1125 if (getSiteElevation(&elev))
1126 {
1127 LocationNP[LOCATION_ELEVATION].setValue(elev);
1128 }
1129 else
1130 {
1131 LOG_ERROR("Error getting site elevation");
1132 }
1133
1134 LocationNP.apply();
1135 return true;
1136}
1137
1138/*
1139 * Set Guide Rate - :SXR0:dddd# (v1.2 and above) where ddd is guide rate * 100
1140 */
1141bool LX200_TeenAstro::SetGuideRate(float guideRate)
1142{
1143 char cmdString[20];
1144
1145 snprintf (cmdString, sizeof(cmdString), guideSpeedCommand, (int) (guideRate * 100));
1146 sendCommand(cmdString);
1147
1148 return true;
1149}
1150
1151
1152/*
1153 * Guidexxx - use SendPulseCmd function from lx200driver.cpp
1154 */
1156{
1159 return IPS_ALERT;
1160
1161 if (GuideNSTID)
1162 {
1163 IERmTimer(GuideNSTID);
1164 GuideNSTID = 0;
1165 }
1166
1167 GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperNS, this);
1168 return IPS_BUSY;
1169}
1170
1172{
1175 return IPS_ALERT;
1176
1177 if (GuideNSTID)
1178 {
1179 IERmTimer(GuideNSTID);
1180 GuideNSTID = 0;
1181 }
1182
1183 GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperNS, this);
1184 return IPS_BUSY;
1185}
1186
1188{
1191 return IPS_ALERT;
1192
1193 if (GuideWETID)
1194 {
1195 IERmTimer(GuideWETID);
1196 GuideWETID = 0;
1197 }
1198
1199 GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperWE, this);
1200 return IPS_BUSY;
1201}
1202
1204{
1207 return IPS_ALERT;
1208
1209 if (GuideWETID)
1210 {
1211 IERmTimer(GuideWETID);
1212 GuideWETID = 0;
1213 }
1214
1215 GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperWE, this);
1216 return IPS_BUSY;
1217}
1218
1219void LX200_TeenAstro::SendPulseCmd(int8_t direction, uint32_t duration_msec)
1220{
1221 ::SendPulseCmd(PortFD, direction, duration_msec);
1222}
1223
1224
1225/*
1226 * Abort() calls standard lx200driver command (:Q#)
1227 */
1229{
1230 if (!isSimulation() && abortSlew(PortFD) < 0)
1231 {
1232 LOG_ERROR("Failed to abort slew.");
1233 return false;
1234 }
1235
1238 EqNP.apply();
1239
1240 LOG_INFO("Slew aborted.");
1241 return true;
1242}
1243
1244/*
1245 * MoveNS and MoveWE call lx200telescope functions
1246 */
1248{
1249 if (dirns == DIRECTION_NORTH)
1250 return Move(LX200_NORTH, cmd);
1251 else
1252 return Move(LX200_SOUTH, cmd);
1253}
1255{
1256 if (dirwe == DIRECTION_WEST)
1257 return Move(LX200_WEST, cmd);
1258 else
1259 return Move(LX200_EAST, cmd);
1260}
1261
1262/*
1263 * Single function for move - use LX200 functions
1264 */
1265bool LX200_TeenAstro::Move(TDirection dir, TelescopeMotionCommand cmd)
1266{
1267 switch (cmd)
1268 {
1269 case MOTION_START:
1270 MoveTo(PortFD, dir);
1271 break;
1272 case MOTION_STOP:
1273 HaltMovement(PortFD, dir);
1274 break;
1275 }
1276 return true;
1277}
1278
1279/*
1280 * Override default config saving
1281 */
1283{
1284 IUSaveConfigSwitch(fp, &SlewRateSP);
1285 IUSaveConfigNumber(fp, &GuideRateNP);
1286
1288}
1289
1290
1291/*
1292 * Mount simulation
1293 */
1294void LX200_TeenAstro::mountSim()
1295{
1296 static struct timeval ltv;
1297 struct timeval tv;
1298 double dt, da, dx;
1299 int nlocked;
1300
1301 /* update elapsed time since last poll, don't presume exactly POLLMS */
1302 gettimeofday(&tv, nullptr);
1303
1304 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1305 ltv = tv;
1306
1307 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1308 ltv = tv;
1309 da = SLEWRATE * dt;
1310
1311 /* Process per current state. We check the state of EQUATORIAL_COORDS and act accordingly */
1312 switch (TrackState)
1313 {
1314 case SCOPE_TRACKING:
1315 /* RA moves at sidereal, Dec stands still */
1316 currentRA += (SIDRATE * dt / 15.);
1317 break;
1318
1319 case SCOPE_SLEWING:
1320 /* slewing - nail it when both within one pulse @ SLEWRATE */
1321 nlocked = 0;
1322
1323 dx = targetRA - currentRA;
1324
1325 if (fabs(dx) <= da)
1326 {
1327 currentRA = targetRA;
1328 nlocked++;
1329 }
1330 else if (dx > 0)
1331 currentRA += da / 15.;
1332 else
1333 currentRA -= da / 15.;
1334
1335 dx = targetDEC - currentDEC;
1336 if (fabs(dx) <= da)
1337 {
1338 currentDEC = targetDEC;
1339 nlocked++;
1340 }
1341 else if (dx > 0)
1342 currentDEC += da;
1343 else
1344 currentDEC -= da;
1345
1346 if (nlocked == 2)
1347 {
1349 }
1350
1351 break;
1352
1353 default:
1354 break;
1355 }
1356
1358}
1359
1360void LX200_TeenAstro::slewError(int slewCode)
1361{
1363
1364 if (slewCode == 1)
1365 {
1366 LOG_INFO("Object below horizon");
1367 EqNP.apply();
1368 }
1369 else if (slewCode == 2)
1370 {
1371 LOG_INFO("Object below the minimum elevation limit.");
1372 EqNP.apply();
1373 }
1374 else
1375 {
1376 LOG_ERROR("Slew failed.");
1377 EqNP.apply();
1378 }
1379}
1380/*
1381 * Enable or disable sidereal tracking (events handled by inditelescope)
1382 */
1384{
1385 LOGF_INFO("TrackEnable %d", enabled);
1386
1387 if (enabled)
1388 {
1389 sendCommand(":Te#");
1390 }
1391 else
1392 {
1393 sendCommand(":Td#");
1394 }
1395 return true;
1396}
1397
1398/*
1399 * selectSlewrate - select among TeenAstro's 5 predefined rates
1400 */
1401bool LX200_TeenAstro::selectSlewRate(int index)
1402{
1403 char cmd[20];
1404
1405 snprintf(cmd, sizeof(cmd), ":R%d#", index);
1406 sendCommand(cmd);
1407 return true;
1408}
1409
1410
1411/*
1412 * Used instead of getCommandString when response is not terminated with '#'
1413 *
1414 */
1415void LX200_TeenAstro::sendCommand(const char *cmd)
1416{
1417 char resp;
1418 int nbytes_read;
1419 std::unique_lock<std::mutex> guard(lx200CommsLock);
1420 LOGF_INFO("sendCommand %s", cmd);
1421 int rc = write(PortFD, cmd, strlen(cmd));
1422 rc = tty_read(PortFD, &resp, 1, ONSTEP_TIMEOUT, &nbytes_read);
1423 INDI_UNUSED(rc);
1424}
1425
1426void LX200_TeenAstro::guideTimeoutHelperNS(void * p)
1427{
1428 static_cast<LX200_TeenAstro *>(p)->guideTimeoutNS();
1429}
1430
1431void LX200_TeenAstro::guideTimeoutHelperWE(void * p)
1432{
1433 static_cast<LX200_TeenAstro *>(p)->guideTimeoutWE();
1434}
1435
1436void LX200_TeenAstro::guideTimeoutNS()
1437{
1438 GuideNSNP[0].setValue(0);
1439 GuideNSNP[1].setValue(0);
1441 GuideNSTID = 0;
1442 GuideNSNP.apply();
1443}
1444
1445void LX200_TeenAstro::guideTimeoutWE()
1446{
1447 GuideWENP[0].setValue(0);
1448 GuideWENP[1].setValue(0);
1450 GuideWETID = 0;
1451 GuideWENP.apply();
1452}
bool isConnected() const
INDI::PropertyText getText(const char *name) const
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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.
uint32_t getDriverInterface() const
INDI::PropertyNumber GuideNSNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyNumber GuideWENP
void initProperties(const char *groupName)
Initialize guider properties. It is recommended to call this function within initProperties() of your...
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
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.
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....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
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+.
Class to provide general functionality of a telescope device.
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,...
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer() or IEAddPeriodicTimer().
Definition eventloop.c:606
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition eventloop.c:586
INDI::PropertySwitch ParkSP
INDI::PropertySwitch AbortSP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertyText TimeTP
INDI::PropertySwitch MovementWESP
INDI::PropertySwitch ParkOptionSP
INDI::PropertyNumber LocationNP
#define currentDEC
Definition ieq45.cpp:48
#define currentRA
Definition ieq45.cpp:47
#define SLEWRATE
Definition ieqpro.cpp:35
double ra
double dec
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition indiapi.h:498
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
#define MAXINDINAME
Definition indiapi.h:189
INDI_DIR_WE
@ DIRECTION_WEST
INDI_DIR_NS
@ DIRECTION_NORTH
void getSexComponents(double value, int *d, int *m, int *s)
Definition indicom.c:243
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
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:130
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition indidevapi.c:265
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:490
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition indidevapi.c:337
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
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:509
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition indidevapi.c:44
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
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:376
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:416
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:398
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:453
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#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 getDeviceName
#define SIDRATE
std::mutex lx200CommsLock
#define ONSTEP_TIMEOUT
#define INITIAL_GUIDE_RATE
#define RB_MAX_LEN
std::mutex lx200CommsLock
#define FIRMWARE_TAB
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)
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)
#define getVersionDate(fd, x)
#define getVersionTime(fd, x)
#define getLX200DEC(fd, x)
#define getVersionNumber(fd, x)
#define getLX200RA(fd, x)
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)
#define getLocalTime24(fd, x)
#define slewToPark(fd)
Namespace to encapsulate INDI client, drivers, and mediator classes.
uint8_t 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.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
One text descriptor.
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248
char * text
Definition indiapi.h:230