26 #include <libnova/transform.h>
35 #define SIDRATE 0.004178
76 IUFillSwitchVector(&HomeSP, HomeS, 1,
getDeviceName(),
"Home",
"Home",
MAIN_CONTROL_TAB,
IP_RW,
ISR_ATMOST1, 0,
80 IUFillNumber(&GuideRateN[0],
"GUIDE_RATE",
"x Sidereal",
"%g", 0.1, 1.0, 0.1, 0.5);
116 const struct timespec timeout = {0, 50000000L};
117 char initCMD[] =
":V#";
122 int nbytes_written = 0;
124 LOG_DEBUG(
"Initializing IOptron using :V# CMD...");
126 for (
int i = 0; i < 2; i++)
132 nanosleep(&timeout,
nullptr);
140 nanosleep(&timeout,
nullptr);
146 response[nbytes_read] =
'\0';
149 if (!strcmp(response,
"V1.00#"))
153 nanosleep(&timeout,
nullptr);
163 if (strcmp(HomeSP.
name, name) == 0)
169 LOG_WARN(
"Telescope is already homed.");
176 if (gotoZEQ25Home() < 0)
179 LOG_ERROR(
"Error slewing to home position.");
184 LOG_INFO(
"Slewing to home position.");
200 if (!strcmp(name, GuideRateNP.
name))
204 if (setZEQ25GuideRate(GuideRateN[0].value) ==
TTY_OK)
218 bool LX200ZEQ25::isZEQ25Home()
220 const struct timespec timeout = {0, 10000000L};
223 int nbytes_write = 0, nbytes_read = 0;
236 nanosleep(&timeout,
nullptr);
237 tcflush(
PortFD, TCIFLUSH);
238 nanosleep(&timeout,
nullptr);
245 return (bool_return[0] ==
'1');
248 int LX200ZEQ25::gotoZEQ25Home()
250 return setZEQ25StandardProcedure(
PortFD,
":MH#");
259 int nbytes_written = 0;
262 const char *
cmd =
":SE#";
266 tcflush(
PortFD, TCIOFLUSH);
284 response[nbytes_read] =
'\0';
287 tcflush(
PortFD, TCIFLUSH);
289 if (response[0] ==
'0')
295 LOGF_ERROR(
"Only received #%d bytes, expected 1.", nbytes_read);
299 bool LX200ZEQ25::getMountInfo()
301 char cmd[] =
":MountInfo#";
306 int nbytes_written = 0;
326 response[nbytes_read] =
'\0';
329 if (nbytes_read == 4)
331 if (!strcmp(response,
"8407"))
332 LOG_INFO(
"Detected iEQ45/iEQ30 Mount.");
333 else if (!strcmp(response,
"8497"))
334 LOG_INFO(
"Detected iEQ45 AA Mount.");
335 else if (!strcmp(response,
"8408"))
337 else if (!strcmp(response,
"8498"))
338 LOG_INFO(
"Detected SmartEQ Mount.");
340 LOG_INFO(
"Unknown mount detected.");
342 tcflush(
PortFD, TCIFLUSH);
348 LOGF_ERROR(
"Only received #%d bytes, expected 4.", nbytes_read);
380 bool isMountParked = isZEQ25Parked();
385 LOG_DEBUG(
"Checking if mount is at home position...");
394 double guideRate = 0;
395 if (getZEQ25GuideRate(&guideRate) ==
TTY_OK)
397 GuideRateN[0].value = guideRate;
426 LOG_INFO(
"Synchronization successful.");
437 const struct timespec timeout = {0, 100000000L};
441 char RAStr[64], DecStr[64];
473 nanosleep(&timeout,
nullptr);
485 if (slewZEQ25() ==
false)
488 LOGF_DEBUG(
"Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
497 LOGF_INFO(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
501 bool LX200ZEQ25::slewZEQ25()
506 int nbytes_write = 0, nbytes_read = 0;
522 tcflush(
PortFD, TCIFLUSH);
526 return (slewNum[0] ==
'1');
539 int nbytes_written = 0;
541 snprintf(
cmd, 8,
":SR%d#", index + 1);
561 response[nbytes_read] =
'\0';
564 tcflush(
PortFD, TCIFLUSH);
566 return (response[0] ==
'1');
569 LOGF_ERROR(
"Only received #%d bytes, expected 1.", nbytes_read);
573 int LX200ZEQ25::getZEQ25MoveRate()
585 int nbytes_written = 0;
605 response[nbytes_read - 1] =
'\0';
608 tcflush(
PortFD, TCIFLUSH);
617 LOGF_ERROR(
"Only received #%d bytes, expected 2.", nbytes_read);
623 struct ln_zonedate ltm;
628 ln_date_to_zonedate(utc, <m, utc_offset * 3600.0);
630 JD = ln_get_julian_day(utc);
641 if (setZEQ25Date(ltm.days, ltm.months, ltm.years) < 0)
647 if (setZEQ25UTCOffset(utc_offset) < 0)
663 double final_longitude;
666 final_longitude = longitude - 360.0;
668 final_longitude = longitude;
670 if (!
isSimulation() && setZEQ25Longitude(final_longitude) < 0)
672 LOG_ERROR(
"Error setting site longitude coordinates");
678 LOG_ERROR(
"Error setting site latitude coordinates");
684 fs_sexa(L, longitude, 4, 3600);
686 LOGF_INFO(
"Site location updated to Lat %.32s - Long %.32s", l, L);
691 int LX200ZEQ25::setZEQ25Longitude(
double Long)
695 char temp_string[32];
704 snprintf(temp_string,
sizeof(temp_string),
":Sg %c%03d:%02d:%02d#", sign, abs(d), m, s);
706 return (setZEQ25StandardProcedure(
PortFD, temp_string));
709 int LX200ZEQ25::setZEQ25Latitude(
double Lat)
713 char temp_string[32];
722 snprintf(temp_string,
sizeof(temp_string),
":St %c%02d:%02d:%02d#", sign, abs(d), m, s);
724 return (setZEQ25StandardProcedure(
PortFD, temp_string));
727 int LX200ZEQ25::setZEQ25UTCOffset(
double hours)
729 char temp_string[16];
731 int h = 0, m = 0, s = 0;
740 snprintf(temp_string,
sizeof(temp_string),
":SG %c%02d:%02d#", sign, abs(h), m);
742 return (setZEQ25StandardProcedure(
PortFD, temp_string));
745 int LX200ZEQ25::setZEQ25Date(
int days,
int months,
int years)
747 char command[16] = {0};
748 snprintf(command,
sizeof(command),
":SC %02d/%02d/%02d#", months, days, years % 100);
749 return (setZEQ25StandardProcedure(
PortFD, command));
752 int LX200ZEQ25::setZEQ25StandardProcedure(
int fd,
const char *data)
754 const struct timespec timeout = {0, 10000000L};
757 int nbytes_write = 0, nbytes_read = 0;
764 error_type =
tty_read(
fd, bool_return, 1, 5, &nbytes_read);
767 nanosleep(&timeout,
nullptr);
768 tcflush(
fd, TCIFLUSH);
769 nanosleep(&timeout,
nullptr);
776 if (bool_return[0] ==
'0')
796 LOG_ERROR(
"Error setting N/S motion direction.");
801 (current_move ==
LX200_NORTH) ?
"North" :
"South");
812 (current_move ==
LX200_NORTH) ?
"North" :
"South");
828 LOG_ERROR(
"Error setting W/E motion direction.");
843 (current_move ==
LX200_WEST) ?
"West" :
"East");
850 int LX200ZEQ25::moveZEQ25To(
int direction)
853 int nbytes_write = 0;
877 tcflush(
PortFD, TCIFLUSH);
881 int LX200ZEQ25::haltZEQ25Movement()
885 int nbytes_write = 0;
890 tcflush(
PortFD, TCIFLUSH);
896 return (setZEQ25TrackMode(mode) == 0);
899 int LX200ZEQ25::setZEQ25TrackMode(
int mode)
908 snprintf(
cmd, 6,
":RT%d#", mode);
910 return setZEQ25StandardProcedure(
PortFD,
cmd);
913 int LX200ZEQ25::setZEQ25Park()
916 int nbytes_write = 0;
923 tcflush(
PortFD, TCIFLUSH);
927 int LX200ZEQ25::setZEQ25UnPark()
930 int nbytes_write = 0;
937 tcflush(
PortFD, TCIFLUSH);
941 bool LX200ZEQ25::isZEQ25Parked()
953 int nbytes_written = 0;
973 response[nbytes_read] =
'\0';
976 tcflush(
PortFD, TCIFLUSH);
978 return (response[0] ==
'1');
981 LOGF_ERROR(
"Only received #%d bytes, expected 1.", nbytes_read);
992 double parkAZ = horizontalPos.
azimuth;
993 double parkAlt = horizontalPos.
altitude;
995 char AzStr[16], AltStr[16];
996 fs_sexa(AzStr, parkAZ, 2, 3600);
997 fs_sexa(AltStr, parkAlt, 2, 3600);
999 LOGF_DEBUG(
"Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr,
1023 if (gotoZEQ25Home() < 0)
1035 LOG_INFO(
"Parking is in progress...");
1042 char AzStr[16], AltStr[16];
1043 fs_sexa(AzStr, parkAz, 2, 3600);
1044 fs_sexa(AltStr, parkAlt, 2, 3600);
1046 LOGF_DEBUG(
"Parking to Az (%s) Alt (%s)...", AzStr, AltStr);
1051 horizontalPos.alt = parkAlt;
1052 horizontalPos.az = parkAz + 180;
1053 if (horizontalPos.az > 360)
1054 horizontalPos.az -= 360;
1056 IGeographicCoordinates observer;
1059 if (observer.lng > 180)
1060 observer.lng -= 360;
1063 ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos);
1073 if (slewZEQ25() ==
false)
1075 LOGF_ERROR(
"Error Slewing to Az %s - Alt %s", AzStr, AltStr);
1082 LOG_INFO(
"Parking is in progress...");
1093 if (setZEQ25UnPark() < 0)
1105 char AzStr[16], AltStr[16];
1106 fs_sexa(AzStr, parkAz, 2, 3600);
1107 fs_sexa(AltStr, parkAlt, 2, 3600);
1108 LOGF_DEBUG(
"Syncing to parked coordinates Az (%s) Alt (%s)...", AzStr, AltStr);
1113 horizontalPos.alt = parkAlt;
1114 horizontalPos.az = parkAz + 180;
1115 if (horizontalPos.az > 360)
1116 horizontalPos.az -= 360;
1118 IGeographicCoordinates observer;
1121 if (observer.lng > 180)
1122 observer.lng -= 360;
1125 ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos);
1165 LOG_INFO(
"Telescope arrived at home position.");
1176 LOG_INFO(
"Slew is complete. Tracking...");
1204 if (getZEQ25PierSide(side))
1212 void LX200ZEQ25::mountSim()
1214 static struct timeval ltv;
1220 gettimeofday(&tv,
nullptr);
1222 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1225 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1280 if (getZEQ25PierSide(side))
1286 int LX200ZEQ25::getZEQ25GuideRate(
double *rate)
1288 char cmd[] =
":AG#";
1292 int nbytes_read = 0;
1293 int nbytes_written = 0;
1299 snprintf(response, 8,
"%3d#",
static_cast<int>(GuideRateN[0].value * 100));
1300 nbytes_read = strlen(response);
1304 tcflush(
PortFD, TCIFLUSH);
1321 if (nbytes_read > 0)
1323 response[nbytes_read] =
'\0';
1328 if (sscanf(response,
"%d#", &rate_num) > 0)
1330 *rate = rate_num / 100.0;
1331 tcflush(
PortFD, TCIFLUSH);
1336 LOGF_ERROR(
"Error: Malformed result (%s).", response);
1341 LOGF_ERROR(
"Only received #%d bytes, expected 1.", nbytes_read);
1345 int LX200ZEQ25::setZEQ25GuideRate(
double rate)
1351 int nbytes_read = 0;
1352 int nbytes_written = 0;
1354 int num = rate * 100;
1355 snprintf(
cmd, 16,
":RG%03d#", num);
1361 strcpy(response,
"1");
1362 nbytes_read = strlen(response);
1366 tcflush(
PortFD, TCIFLUSH);
1383 if (nbytes_read > 0)
1385 response[nbytes_read] =
'\0';
1388 tcflush(
PortFD, TCIFLUSH);
1392 LOGF_ERROR(
"Only received #%d bytes, expected 1.", nbytes_read);
1398 int nbytes_write = 0;
1403 sprintf(
cmd,
":Mn%04d#", duration_msec);
1406 sprintf(
cmd,
":Ms%04d#", duration_msec);
1409 sprintf(
cmd,
":Me%04d#", duration_msec);
1412 sprintf(
cmd,
":Mw%04d#", duration_msec);
1422 tcflush(
PortFD, TCIFLUSH);
1426 bool LX200ZEQ25::getZEQ25PierSide(TelescopePierSide &side)
1428 int nbytes_written = 0;
1431 char response[8] = {0};
1432 int nbytes_read = 0;
1436 strcpy(response,
"1");
1437 nbytes_read = strlen(response);
1441 tcflush(
PortFD, TCIFLUSH);
1458 if (nbytes_read > 0)
1460 response[nbytes_read] =
'\0';
1463 if ( response[0] ==
'0')
1465 else if ( response[0] ==
'1')
1479 char command[64] = {0};
1482 snprintf(command, 64,
":SG %c%02d:%02d#", offset >= 0 ?
'+' :
'-', h, m);
1483 return setZEQ25StandardProcedure(
PortFD, command);
const char * getDeviceName() const
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
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
double GetAxis1Park() const
double GetAxis2Park() const
bool isParked()
isParked is mount currently parked?
ISwitchVectorProperty SlewRateSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
IGeographicCoordinates m_Location
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
ISwitchVectorProperty MovementWESP
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void slewError(int slewCode)
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool sendScopeLocation()
bool sendLocationOnStartup
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
@ LX200_HAS_PULSE_GUIDING
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool sendScopeTime()
void setLX200Capability(uint32_t cap)
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual const char * getDefaultName() override
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual int SendPulseCmd(int8_t direction, uint32_t duration_msec) override
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
virtual void getBasicData() override
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool Park() override
Park the telescope to its home position.
virtual bool checkConnection() override
virtual bool setUTCOffset(double offset) override
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool Sync(double, double) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool isSlewComplete() override
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
#define setLocalTime(fd, x, y, z)
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
void getSexComponents(double value, int *d, int *m, int *s)
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
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[].
Implementations for common driver routines.
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.
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
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.
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.
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.
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.
#define LOGF_INFO(fmt,...)
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
#define DEBUGF(priority, msg,...)
int setObjectRA(int fd, double ra, bool addSpace)
int setObjectDEC(int fd, double dec, bool addSpace)
#define getLX200DEC(fd, x)
#define getLX200RA(fd, x)
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.