Instrument Neutral Distributed Interface INDI 2.2.5
ieqprolegacy.cpp
Go to the documentation of this file.
1/*
2 INDI IEQ Pro driver
3
4 Copyright (C) 2015 Jasem Mutlaq
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20
21#include "ieqprolegacy.h"
22#include "indicom.h"
24
25#include <libnova/sidereal_time.h>
26#include <libnova/transform.h>
27#include <memory>
28
29#include <cmath>
30#include <cstring>
31
32/* Simulation Parameters */
33#define SLEWRATE 1 /* slew rate, degrees/s */
34
35#define MOUNTINFO_TAB "Mount Info"
36
37// We declare an auto pointer to IEQPro.
38static std::unique_ptr<IEQProLegacy> scope(new IEQProLegacy());
39
40/* Constructor */
59
61{
62 return "iEQ";
63}
64
66{
68
69 /* Firmware */
70 IUFillText(&FirmwareT[FW_MODEL], "Model", "", nullptr);
71 IUFillText(&FirmwareT[FW_BOARD], "Board", "", nullptr);
72 IUFillText(&FirmwareT[FW_CONTROLLER], "Controller", "", nullptr);
73 IUFillText(&FirmwareT[FW_RA], "RA", "", nullptr);
74 IUFillText(&FirmwareT[FW_DEC], "DEC", "", nullptr);
75 IUFillTextVector(&FirmwareTP, FirmwareT, 5, getDeviceName(), "Firmware Info", "", MOUNTINFO_TAB, IP_RO, 0,
76 IPS_IDLE);
77
78 /* Tracking Mode */
79 AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
80 AddTrackMode("TRACK_SOLAR", "Solar");
81 AddTrackMode("TRACK_LUNAR", "Lunar");
82 AddTrackMode("TRACK_KING", "King");
83 AddTrackMode("TRACK_CUSTOM", "Custom");
84
85 // Slew Rates
86 SlewRateSP[0].setLabel("1x");
87 SlewRateSP[1].setLabel("2x");
88 SlewRateSP[2].setLabel("8x");
89 SlewRateSP[3].setLabel("16x");
90 SlewRateSP[4].setLabel("64x");
91 SlewRateSP[5].setLabel("128x");
92 SlewRateSP[6].setLabel("256x");
93 SlewRateSP[7].setLabel("512x");
94 SlewRateSP[8].setLabel("MAX");
96 // 64x is the default
98
99 // Set TrackRate limits within +/- 0.0100 of Sidereal rate
100 TrackRateNP[AXIS_RA].setMin(TRACKRATE_SIDEREAL - 0.01);
101 TrackRateNP[AXIS_RA].setMax(TRACKRATE_SIDEREAL + 0.01);
102 TrackRateNP[AXIS_DE].setMin(-0.01);
103 TrackRateNP[AXIS_DE].setMax(0.01);
104
105 /* GPS Status */
106 IUFillSwitch(&GPSStatusS[GPS_OFF], "Off", "", ISS_ON);
107 IUFillSwitch(&GPSStatusS[GPS_ON], "On", "", ISS_OFF);
108 IUFillSwitch(&GPSStatusS[GPS_DATA_OK], "Data OK", "", ISS_OFF);
109 IUFillSwitchVector(&GPSStatusSP, GPSStatusS, 3, getDeviceName(), "GPS_STATUS", "GPS", MOUNTINFO_TAB, IP_RO,
111
112 /* Time Source */
113 IUFillSwitch(&TimeSourceS[TS_RS232], "RS232", "", ISS_ON);
114 IUFillSwitch(&TimeSourceS[TS_CONTROLLER], "Controller", "", ISS_OFF);
115 IUFillSwitch(&TimeSourceS[TS_GPS], "GPS", "", ISS_OFF);
116 IUFillSwitchVector(&TimeSourceSP, TimeSourceS, 3, getDeviceName(), "TIME_SOURCE", "Time Source", MOUNTINFO_TAB,
118
119 /* Hemisphere */
120 IUFillSwitch(&HemisphereS[HEMI_SOUTH], "South", "", ISS_OFF);
121 IUFillSwitch(&HemisphereS[HEMI_NORTH], "North", "", ISS_ON);
122 IUFillSwitchVector(&HemisphereSP, HemisphereS, 2, getDeviceName(), "HEMISPHERE", "Hemisphere", MOUNTINFO_TAB, IP_RO,
124
125 /* Home */
126 IUFillSwitch(&HomeS[IEQ_FIND_HOME], "FindHome", "Find Home", ISS_OFF);
127 IUFillSwitch(&HomeS[IEQ_SET_HOME], "SetCurrentAsHome", "Set current as Home", ISS_OFF);
128 IUFillSwitch(&HomeS[IEQ_GOTO_HOME], "GoToHome", "Go to Home", ISS_OFF);
129 IUFillSwitchVector(&HomeSP, HomeS, 3, getDeviceName(), "HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0,
130 IPS_IDLE);
131
132 /* How fast do we guide compared to sidereal rate */
133 IUFillNumber(&GuideRateN[RA_AXIS], "RA_GUIDE_RATE", "x Sidereal", "%.2f", 0.01, 0.9, 0.1, 0.5);
134 IUFillNumber(&GuideRateN[DEC_AXIS], "DE_GUIDE_RATE", "x Sidereal", "%.2f", 0.1, 0.99, 0.1, 0.5);
135 IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0,
136 IPS_IDLE);
137
139
141
143
145
147
149
150 // Only CEM40 and GEM45 have 115200 baud, rest are 9600
151 if (strstr(getDeviceName(), "CEM40") || strstr(getDeviceName(), "GEM45"))
153
155 currentDEC = LocationNP[LOCATION_LATITUDE].getValue() > 0 ? 90 : -90;
156 return true;
157}
158
160{
162
163 if (isConnected())
164 {
165 defineProperty(&HomeSP);
166
167 defineProperty(&GuideRateNP);
168
169 defineProperty(&FirmwareTP);
170 defineProperty(&GPSStatusSP);
171 defineProperty(&TimeSourceSP);
172 defineProperty(&HemisphereSP);
173
174 getStartupData();
175 }
176 else
177 {
178 deleteProperty(HomeSP.name);
179
180 deleteProperty(GuideRateNP.name);
181
182 deleteProperty(FirmwareTP.name);
183 deleteProperty(GPSStatusSP.name);
184 deleteProperty(TimeSourceSP.name);
185 deleteProperty(HemisphereSP.name);
186 }
187
189
190 return true;
191}
192
193void IEQProLegacy::getStartupData()
194{
195 LOG_DEBUG("Getting firmware data...");
196 if (get_ieqpro_firmware(PortFD, &firmwareInfo))
197 {
198 IUSaveText(&FirmwareT[0], firmwareInfo.Model.c_str());
199 IUSaveText(&FirmwareT[1], firmwareInfo.MainBoardFirmware.c_str());
200 IUSaveText(&FirmwareT[2], firmwareInfo.ControllerFirmware.c_str());
201 IUSaveText(&FirmwareT[3], firmwareInfo.RAFirmware.c_str());
202 IUSaveText(&FirmwareT[4], firmwareInfo.DEFirmware.c_str());
203
204 FirmwareTP.s = IPS_OK;
205 IDSetText(&FirmwareTP, nullptr);
206 }
207
208 LOG_DEBUG("Getting guiding rate...");
209 double raGuideRate = 0, deGuideRate = 0;
210 if (get_ieqpro_guide_rate(PortFD, &raGuideRate, &deGuideRate))
211 {
212 GuideRateN[RA_AXIS].value = raGuideRate;
213 GuideRateN[DEC_AXIS].value = deGuideRate;
214 IDSetNumber(&GuideRateNP, nullptr);
215 }
216
217 double utc_offset;
218 int yy, dd, mm, hh, minute, ss;
219 if (get_ieqpro_utc_date_time(PortFD, &utc_offset, &yy, &mm, &dd, &hh, &minute, &ss))
220 {
221 char isoDateTime[32] = {0};
222 char utcOffset[8] = {0};
223
224 snprintf(isoDateTime, 32, "%04d-%02d-%02dT%02d:%02d:%02d", yy, mm, dd, hh, minute, ss);
225 snprintf(utcOffset, 8, "%4.2f", utc_offset);
226
227 TimeTP[UTC].setText(isoDateTime);
228 TimeTP[OFFSET].setText(utcOffset);
229
230 LOGF_INFO("Mount UTC offset is %s. UTC time is %s", utcOffset, isoDateTime);
231
233 TimeTP.apply();
234 }
235
236 // Get Longitude and Latitude from mount
237 double longitude = 0, latitude = 0;
238 if (get_ieqpro_latitude(PortFD, &latitude) && get_ieqpro_longitude(PortFD, &longitude))
239 {
240 // Convert to INDI standard longitude (0 to 360 Eastward)
241 if (longitude < 0)
242 longitude += 360;
243
244 LOGF_INFO("Mount Longitude %g Latitude %g", longitude, latitude);
245
246 LocationNP[LOCATION_LATITUDE].setValue(latitude);
247 LocationNP[LOCATION_LONGITUDE].setValue(longitude);
249
250 LocationNP.apply(nullptr);
251
252 saveConfig(true, "GEOGRAPHIC_COORD");
253 }
254 else if (IUGetConfigNumber(getDeviceName(), "GEOGRAPHIC_COORD", "LONG", &longitude) == 0 &&
255 IUGetConfigNumber(getDeviceName(), "GEOGRAPHIC_COORD", "LAT", &latitude) == 0)
256 {
257 LocationNP[LOCATION_LATITUDE].setValue(latitude);
258 LocationNP[LOCATION_LONGITUDE].setValue(longitude);
260
262 }
263
264 if (InitPark())
265 {
266 // If loading parking data is successful, we just set the default parking values.
267 SetAxis1ParkDefault(LocationNP[LOCATION_LATITUDE].getValue() >= 0 ? 0 : 180);
269 }
270 else
271 {
272 // Otherwise, we set all parking data to default in case no parking data is found.
273 SetAxis1Park(LocationNP[LOCATION_LATITUDE].getValue() >= 0 ? 0 : 180);
275 SetAxis1ParkDefault(LocationNP[LOCATION_LATITUDE].getValue() >= 0 ? 0 : 180);
277 }
278
279 if (isSimulation())
280 {
281 if (isParked())
283 else
285 }
286}
287
288bool IEQProLegacy::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
289{
290 // Check guider interface
291 if (GI::processNumber(dev, name, values, names, n))
292 return true;
293
294 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
295 {
296 // Guiding Rate
297 if (!strcmp(name, GuideRateNP.name))
298 {
299 IUUpdateNumber(&GuideRateNP, values, names, n);
300
301 if (set_ieqpro_guide_rate(PortFD, GuideRateN[RA_AXIS].value, GuideRateN[DEC_AXIS].value))
302 GuideRateNP.s = IPS_OK;
303 else
304 GuideRateNP.s = IPS_ALERT;
305
306 IDSetNumber(&GuideRateNP, nullptr);
307
308 return true;
309 }
310 }
311
312 return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
313}
314
315bool IEQProLegacy::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
316{
317 if (!strcmp(getDeviceName(), dev))
318 {
319 if (!strcmp(name, HomeSP.name))
320 {
321 IUUpdateSwitch(&HomeSP, states, names, n);
322
323 IEQ_HOME_OPERATION operation = static_cast<IEQ_HOME_OPERATION>(IUFindOnSwitchIndex(&HomeSP));
324
325 IUResetSwitch(&HomeSP);
326
327 switch (operation)
328 {
329 case IEQ_FIND_HOME:
330 if (firmwareInfo.Model.find("CEM") == std::string::npos)
331 {
332 HomeSP.s = IPS_IDLE;
333 IDSetSwitch(&HomeSP, nullptr);
334 LOG_WARN("Home search is not supported in this model.");
335 return true;
336 }
337
338 if (find_ieqpro_home(PortFD) == false)
339 {
340 HomeSP.s = IPS_ALERT;
341 IDSetSwitch(&HomeSP, nullptr);
342 return false;
343 }
344
345 HomeSP.s = IPS_OK;
346 IDSetSwitch(&HomeSP, nullptr);
347 LOG_INFO("Searching for home position...");
348 return true;
349
350 case IEQ_SET_HOME:
351 if (set_ieqpro_current_home(PortFD) == false)
352 {
353 HomeSP.s = IPS_ALERT;
354 IDSetSwitch(&HomeSP, nullptr);
355 return false;
356 }
357
358 HomeSP.s = IPS_OK;
359 IDSetSwitch(&HomeSP, nullptr);
360 LOG_INFO("Home position set to current coordinates.");
361 return true;
362
363 case IEQ_GOTO_HOME:
364 if (goto_ieqpro_home(PortFD) == false)
365 {
366 HomeSP.s = IPS_ALERT;
367 IDSetSwitch(&HomeSP, nullptr);
368 return false;
369 }
370
371 HomeSP.s = IPS_OK;
372 IDSetSwitch(&HomeSP, nullptr);
373 LOG_INFO("Slewing to home position...");
374 return true;
375 }
376
377 return true;
378 }
379 }
380
381 return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
382}
383
385{
386 bool rc = false;
387
388 IEQInfo newInfo;
389
390 if (isSimulation())
391 mountSim();
392
393 rc = get_ieqpro_status(PortFD, &newInfo);
394
395 if (rc)
396 {
397 IUResetSwitch(&GPSStatusSP);
398 GPSStatusS[newInfo.gpsStatus].s = ISS_ON;
399 IDSetSwitch(&GPSStatusSP, nullptr);
400
401 IUResetSwitch(&TimeSourceSP);
402 TimeSourceS[newInfo.timeSource].s = ISS_ON;
403 IDSetSwitch(&TimeSourceSP, nullptr);
404
405 IUResetSwitch(&HemisphereSP);
406 HemisphereS[newInfo.hemisphere].s = ISS_ON;
407 IDSetSwitch(&HemisphereSP, nullptr);
408
409 /*
410 TelescopeTrackMode trackMode = TRACK_SIDEREAL;
411
412 switch (newInfo.trackRate)
413 {
414 case TR_SIDEREAL:
415 trackMode = TRACK_SIDEREAL;
416 break;
417 case TR_SOLAR:
418 trackMode = TRACK_SOLAR;
419 break;
420 case TR_LUNAR:
421 trackMode = TRACK_LUNAR;
422 break;
423 case TR_KING:
424 trackMode = TRACK_SIDEREAL;
425 break;
426 case TR_CUSTOM:
427 trackMode = TRACK_CUSTOM;
428 break;
429 }*/
430
431 switch (newInfo.systemStatus)
432 {
433 case ST_STOPPED:
436 break;
437 case ST_PARKED:
440 if (!isParked())
441 SetParked(true);
442 break;
443 case ST_HOME:
446 break;
447 case ST_SLEWING:
451 break;
454 case ST_GUIDING:
455 // If slew to parking position is complete, issue park command now.
458 else
459 {
462 if (scopeInfo.systemStatus == ST_SLEWING)
463 LOG_INFO("Slew complete, tracking...");
464 else if (scopeInfo.systemStatus == ST_MERIDIAN_FLIPPING)
465 LOG_INFO("Meridian flip complete, tracking...");
466 }
467 break;
468 }
469
473
474 scopeInfo = newInfo;
475 }
476
477 rc = get_ieqpro_coords(PortFD, &currentRA, &currentDEC);
478
479 if (rc)
480 NewRaDec(currentRA, currentDEC);
481
482 return rc;
483}
484
485bool IEQProLegacy::Goto(double r, double d)
486{
487 targetRA = r;
488 targetDEC = d;
489 char RAStr[64] = {0}, DecStr[64] = {0};
490
491 fs_sexa(RAStr, targetRA, 2, 3600);
492 fs_sexa(DecStr, targetDEC, 2, 3600);
493
494 if (set_ieqpro_ra(PortFD, r) == false || set_ieqpro_dec(PortFD, d) == false)
495 {
496 LOG_ERROR("Error setting RA/DEC.");
497 return false;
498 }
499
500 if (slew_ieqpro(PortFD) == false)
501 {
502 LOG_ERROR("Failed to slew.");
503 return false;
504 }
505
507
508 LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
509 return true;
510}
511
512bool IEQProLegacy::Sync(double ra, double dec)
513{
514 if (set_ieqpro_ra(PortFD, ra) == false || set_ieqpro_dec(PortFD, dec) == false)
515 {
516 LOG_ERROR("Error setting RA/DEC.");
517 return false;
518 }
519
520 if (sync_ieqpro(PortFD) == false)
521 {
522 LOG_ERROR("Failed to sync.");
523 }
524
526
527 currentRA = ra;
528 currentDEC = dec;
529
530 NewRaDec(currentRA, currentDEC);
531
532 return true;
533}
534
536{
537 return abort_ieqpro(PortFD);
538}
539
541{
542#if 0
543 targetRA = GetAxis1Park();
544 targetDEC = GetAxis2Park();
545
546 if (set_ieqpro_ra(PortFD, targetRA) == false || set_ieqpro_dec(PortFD, targetDEC) == false)
547 {
548 LOG_ERROR("Error setting RA/DEC.");
549 return false;
550 }
551
552 if (slew_ieqpro(PortFD) == false)
553 {
554 LOG_ERROR("Failed to slew tp parking position.");
555 return false;
556 }
557
558 char RAStr[64] = {0}, DecStr[64] = {0};
559 fs_sexa(RAStr, targetRA, 2, 3600);
560 fs_sexa(DecStr, targetDEC, 2, 3600);
561
563 LOGF_INFO("Telescope parking in progress to RA: %s DEC: %s", RAStr, DecStr);
564
565 return true;
566#endif
567
568 double parkAz = GetAxis1Park();
569 double parkAlt = GetAxis2Park();
570
571 char AzStr[16], AltStr[16];
572 fs_sexa(AzStr, parkAz, 2, 3600);
573 fs_sexa(AltStr, parkAlt, 2, 3600);
574 LOGF_DEBUG("Parking to Az (%s) Alt (%s)...", AzStr, AltStr);
575
576 INDI::IEquatorialCoordinates equatorialCoords {0, 0};
577 INDI::IHorizontalCoordinates horizontalCoords {parkAz, parkAlt};
578 INDI::HorizontalToEquatorial(&horizontalCoords, &m_Location, ln_get_julian_from_sys(), &equatorialCoords);
579
580 if (Goto(equatorialCoords.rightascension, equatorialCoords.declination))
581 {
583 LOG_INFO("Parking is in progress...");
584
585 return true;
586 }
587 else
588 return false;
589}
590
592{
594 {
595 SetParked(false);
597 return true;
598 }
599 else
600 return false;
601}
602
604{
605 if (isSimulation())
606 {
613 }
614
615 if (check_ieqpro_connection(PortFD) == false)
616 return false;
617
618 return true;
619}
620
621bool IEQProLegacy::updateTime(ln_date *utc, double utc_offset)
622{
623 struct ln_zonedate ltm;
624
625 ln_date_to_zonedate(utc, &ltm, utc_offset * 3600.0);
626
627 // Set Local Time
628 if (set_ieqpro_local_time(PortFD, ltm.hours, ltm.minutes, ltm.seconds) == false)
629 {
630 LOG_ERROR("Error setting local time.");
631 return false;
632 }
633
634 // Send it as YY (i.e. 2015 --> 15)
635 ltm.years -= 2000;
636
637 // Set Local date
638 if (set_ieqpro_local_date(PortFD, ltm.years, ltm.months, ltm.days) == false)
639 {
640 LOG_ERROR("Error setting local date.");
641 return false;
642 }
643
644 // UTC Offset
645 if (set_ieqpro_utc_offset(PortFD, utc_offset) == false)
646 {
647 LOG_ERROR("Error setting UTC Offset.");
648 return false;
649 }
650
651 LOG_INFO("Time and date updated.");
652
653 return true;
654}
655
656bool IEQProLegacy::updateLocation(double latitude, double longitude, double elevation)
657{
658 INDI_UNUSED(elevation);
659
660 if (longitude > 180)
661 longitude -= 360;
662
663 if (set_ieqpro_longitude(PortFD, longitude) == false)
664 {
665 LOG_ERROR("Failed to set longitude.");
666 return false;
667 }
668
669 if (set_ieqpro_latitude(PortFD, latitude) == false)
670 {
671 LOG_ERROR("Failed to set latitude.");
672 return false;
673 }
674
675 char l[32] = {0}, L[32] = {0};
676 fs_sexa(l, latitude, 3, 3600);
677 fs_sexa(L, longitude, 4, 3600);
678
679 LOGF_INFO("Site location updated to Lat %.32s - Long %.32s", l, L);
680
681 return true;
682}
683
685{
686 set_ieqpro_debug(enable);
687}
688
690{
691 set_ieqpro_simulation(enable);
692}
693
695{
697 {
698 LOG_ERROR("Please unpark the mount before issuing any motion commands.");
699 return false;
700 }
701
702 switch (command)
703 {
704 case MOTION_START:
705 if (start_ieqpro_motion(PortFD, (dir == DIRECTION_NORTH ? IEQ_N : IEQ_S)) == false)
706 {
707 LOG_ERROR("Error setting N/S motion direction.");
708 return false;
709 }
710 else
711 LOGF_INFO("Moving toward %s.", (dir == DIRECTION_NORTH) ? "North" : "South");
712 break;
713
714 case MOTION_STOP:
715 if (stop_ieqpro_motion(PortFD, (dir == DIRECTION_NORTH ? IEQ_N : IEQ_S)) == false)
716 {
717 LOG_ERROR("Error stopping N/S motion.");
718 return false;
719 }
720 else
721 LOGF_INFO("%s motion stopped.", (dir == DIRECTION_NORTH) ? "North" : "South");
722 break;
723 }
724
725 return true;
726}
727
729{
731 {
732 LOG_ERROR("Please unpark the mount before issuing any motion commands.");
733 return false;
734 }
735
736 switch (command)
737 {
738 case MOTION_START:
739 if (start_ieqpro_motion(PortFD, (dir == DIRECTION_WEST ? IEQ_W : IEQ_E)) == false)
740 {
741 LOG_ERROR("Error setting N/S motion direction.");
742 return false;
743 }
744 else
745 LOGF_INFO("Moving toward %s.", (dir == DIRECTION_WEST) ? "West" : "East");
746 break;
747
748 case MOTION_STOP:
749 if (stop_ieqpro_motion(PortFD, (dir == DIRECTION_WEST ? IEQ_W : IEQ_E)) == false)
750 {
751 LOG_ERROR("Error stopping W/E motion.");
752 return false;
753 }
754 else
755 LOGF_INFO("%s motion stopped.", (dir == DIRECTION_WEST) ? "West" : "East");
756 break;
757 }
758
759 return true;
760}
761
763{
764 bool rc = start_ieqpro_guide(PortFD, IEQ_N, ms);
765 return (rc ? IPS_OK : IPS_ALERT);
766}
767
769{
770 bool rc = start_ieqpro_guide(PortFD, IEQ_S, ms);
771 return (rc ? IPS_OK : IPS_ALERT);
772}
773
775{
776 bool rc = start_ieqpro_guide(PortFD, IEQ_E, ms);
777 return (rc ? IPS_OK : IPS_ALERT);
778}
779
781{
782 bool rc = start_ieqpro_guide(PortFD, IEQ_W, ms);
783 return (rc ? IPS_OK : IPS_ALERT);
784}
785
787{
788 IEQ_SLEW_RATE rate = static_cast<IEQ_SLEW_RATE>(index);
789 return set_ieqpro_slew_rate(PortFD, rate);
790}
791
793{
795
796 return true;
797}
798
800{
801 static struct timeval ltv;
802 struct timeval tv;
803 double dt, da, dx;
804 int nlocked;
805
806 /* update elapsed time since last poll, don't presume exactly POLLMS */
807 gettimeofday(&tv, nullptr);
808
809 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
810 ltv = tv;
811
812 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
813 ltv = tv;
814 da = SLEWRATE * dt;
815
816 /* Process per current state. We check the state of EQUATORIAL_COORDS and act accordingly */
817 switch (TrackState)
818 {
819 case SCOPE_IDLE:
820 currentRA += (TrackRateNP[AXIS_RA].getValue() / 3600.0 * dt) / 15.0;
822 break;
823
824 case SCOPE_TRACKING:
825 if (TrackModeSP[1].getState() == ISS_ON)
826 {
827 currentRA += ( ((TRACKRATE_SIDEREAL / 3600.0) - (TrackRateNP[AXIS_RA].getValue() / 3600.0)) * dt) / 15.0;
828 currentDEC += ( (TrackRateNP[AXIS_DE].getValue() / 3600.0) * dt);
829 }
830 break;
831
832 case SCOPE_SLEWING:
833 case SCOPE_PARKING:
834 /* slewing - nail it when both within one pulse @ SLEWRATE */
835 nlocked = 0;
836
837 dx = targetRA - currentRA;
838
839 // Take shortest path
840 if (fabs(dx) > 12)
841 dx *= -1;
842
843 if (fabs(dx) <= da)
844 {
845 currentRA = targetRA;
846 nlocked++;
847 }
848 else if (dx > 0)
849 currentRA += da / 15.;
850 else
851 currentRA -= da / 15.;
852
853 if (currentRA < 0)
854 currentRA += 24;
855 else if (currentRA > 24)
856 currentRA -= 24;
857
858 dx = targetDEC - currentDEC;
859 if (fabs(dx) <= da)
860 {
861 currentDEC = targetDEC;
862 nlocked++;
863 }
864 else if (dx > 0)
865 currentDEC += da;
866 else
867 currentDEC -= da;
868
869 if (nlocked == 2)
870 {
873 else
875 }
876
877 break;
878
879 default:
880 break;
881 }
882
885}
886
888{
890 INDI::IHorizontalCoordinates horizontalCoords {0, 0};
891 INDI::EquatorialToHorizontal(&equatorialCoords, &m_Location, ln_get_julian_from_sys(), &horizontalCoords);
892 double parkAZ = horizontalCoords.azimuth;
893 double parkAlt = horizontalCoords.altitude;
894
895 char AzStr[16], AltStr[16];
896 fs_sexa(AzStr, parkAZ, 2, 3600);
897 fs_sexa(AltStr, parkAlt, 2, 3600);
898
899 LOGF_DEBUG("Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr,
900 AltStr);
901
902 SetAxis1Park(parkAZ);
903 SetAxis2Park(parkAlt);
904
905 return true;
906}
907
909{
910 // By default azimuth 0
911 SetAxis1Park(0);
912
913 // Altitude = latitude of observer
915
916 return true;
917}
918
920{
921 IEQ_TRACK_RATE rate = static_cast<IEQ_TRACK_RATE>(mode);
922
923 if (set_ieqpro_track_mode(PortFD, rate))
924 return true;
925
926 return false;
927}
928
929bool IEQProLegacy::SetTrackRate(double raRate, double deRate)
930{
931 static bool deRateWarning = true;
932
933 // Convert to arcsecs/s to +/- 0.0100 accepted by
934 double ieqRARate = raRate - TRACKRATE_SIDEREAL;
935 if (deRate != 0 && deRateWarning)
936 {
937 // Only send warning once per session
938 deRateWarning = false;
939 LOG_WARN("Custom Declination tracking rate is not implemented yet.");
940 }
941
943 return true;
944
945 return false;
946}
947
949{
950 if (enabled)
951 {
952 // If we are engaging tracking, let us first set tracking mode, and if we have custom mode, then tracking rate.
953 // NOTE: Is this the correct order? or should tracking be switched on first before making these changes? Need to test.
955 if (TrackModeSP[TR_CUSTOM].getState() == ISS_ON)
956 SetTrackRate(TrackRateNP[AXIS_RA].getValue(), TrackRateNP[AXIS_DE].getValue());
957 }
958
959 return set_ieqpro_track_enabled(PortFD, enabled);
960}
@ FW_MODEL
@ FW_DEC
@ FW_RA
@ SR_1
@ SR_3
@ GPS_OFF
@ GPS_ON
#define MOUNTINFO_TAB
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
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 SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool Park() override
Park the telescope to its home position.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual const char * getDefaultName() override
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool isConnected() 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
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
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
void setLabel(const char *label)
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
double GetAxis2Park() const
bool isParked()
isParked is mount currently parked?
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
Connection::Serial * serialConnection
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.
IGeographicCoordinates m_Location
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
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.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
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.
INDI::PropertyNumber TrackRateNP
INDI::PropertyNumber EqNP
INDI::PropertySwitch SlewRateSP
INDI::PropertySwitch TrackModeSP
INDI::PropertyText TimeTP
INDI::PropertyNumber LocationNP
#define currentDEC
Definition ieq45.cpp:48
#define currentRA
Definition ieq45.cpp:47
#define SLEWRATE
Definition ieqpro.cpp:35
bool goto_ieqpro_home(int fd)
bool set_ieqpro_latitude(int fd, double latitude)
bool sync_ieqpro(int fd)
bool set_ieqpro_current_home(int fd)
void set_sim_gps_status(IEQ_GPS_STATUS value)
bool start_ieqpro_guide(int fd, IEQ_DIRECTION dir, uint32_t ms)
void set_sim_dec(double dec)
bool find_ieqpro_home(int fd)
bool slew_ieqpro(int fd)
void set_sim_hemisphere(IEQ_HEMISPHERE value)
bool set_ieqpro_local_date(int fd, int yy, int mm, int dd)
bool get_ieqpro_utc_date_time(int fd, double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss)
bool get_ieqpro_status(int fd, IEQInfo *info)
bool set_ieqpro_local_time(int fd, int hh, int mm, int ss)
void set_ieqpro_debug(bool enable)
bool get_ieqpro_coords(int fd, double *ra, double *dec)
bool park_ieqpro(int fd)
double ra
void set_ieqpro_device(const char *name)
void set_ieqpro_simulation(bool enable)
bool get_ieqpro_firmware(int fd, FirmwareInfo *info)
bool set_ieqpro_custom_ra_track_rate(int fd, double rate)
bool set_ieqpro_dec(int fd, double dec)
bool set_ieqpro_guide_rate(int fd, double raRate, double deRate)
bool abort_ieqpro(int fd)
bool unpark_ieqpro(int fd)
bool set_ieqpro_track_mode(int fd, IEQ_TRACK_RATE rate)
void set_sim_system_status(IEQ_SYSTEM_STATUS value)
void set_sim_slew_rate(IEQ_SLEW_RATE value)
bool get_ieqpro_latitude(int fd, double *latitude)
bool check_ieqpro_connection(int fd)
double dec
bool set_ieqpro_ra(int fd, double ra)
bool set_ieqpro_slew_rate(int fd, IEQ_SLEW_RATE rate)
bool get_ieqpro_guide_rate(int fd, double *raRate, double *deRate)
bool start_ieqpro_motion(int fd, IEQ_DIRECTION dir)
void set_sim_time_source(IEQ_TIME_SOURCE value)
bool set_ieqpro_utc_offset(int fd, double offset)
bool set_ieqpro_longitude(int fd, double longitude)
bool get_ieqpro_longitude(int fd, double *longitude)
void set_sim_ra(double ra)
bool set_ieqpro_track_enabled(int fd, bool enabled)
bool stop_ieqpro_motion(int fd, IEQ_DIRECTION dir)
void set_sim_track_rate(IEQ_TRACK_RATE value)
IEQ_HOME_OPERATION
@ IEQ_FIND_HOME
@ IEQ_SET_HOME
@ IEQ_GOTO_HOME
IEQ_TRACK_RATE
@ TR_SIDEREAL
@ TR_CUSTOM
@ TS_RS232
@ TS_CONTROLLER
@ HEMI_NORTH
@ HEMI_SOUTH
IEQ_SLEW_RATE
@ FW_CONTROLLER
@ FW_BOARD
@ GPS_DATA_OK
@ ST_STOPPED
@ ST_MERIDIAN_FLIPPING
@ ST_PARKED
@ ST_TRACKING_PEC_ON
@ ST_TRACKING_PEC_OFF
@ ST_SLEWING
@ ST_GUIDING
@ ST_HOME
#define RA_AXIS
#define DEC_AXIS
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ 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
@ ISR_ATMOST1
Definition indiapi.h:172
@ AXIS_DE
@ AXIS_RA
INDI_DIR_WE
@ DIRECTION_WEST
INDI_DIR_NS
@ DIRECTION_NORTH
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition indicom.c:1311
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
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sidereal time given longitude and system clock.
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 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 IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
IUGetConfigNumber Opens configuration file and reads single number property.
Definition indidriver.c:846
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 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 LOG_INFO(txt)
Definition indilogger.h:74
#define TRACKRATE_SIDEREAL
Definition indimacros.h:39
#define getDeviceName
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
Definition libastro.cpp:141
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
Definition libastro.cpp:161
std::string RAFirmware
std::string ControllerFirmware
std::string Model
std::string DEFirmware
std::string MainBoardFirmware
IEQ_GPS_STATUS gpsStatus
IEQ_SLEW_RATE slewRate
IEQ_TIME_SOURCE timeSource
IEQ_SYSTEM_STATUS systemStatus
IEQ_TRACK_RATE trackRate
IEQ_HEMISPHERE hemisphere
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.
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248