97#include <libnova/transform.h>
106#define SIDRATE 0.004178
107#define ioptronHC8406_TIMEOUT 1
108#define ioptronHC8406_CALDATE_RESULT " # "
128 IUFillSwitchVector(&SyncCMRSP, SyncCMRS, 2,
getDeviceName(),
"SYNC_MODE",
"Sync",
MAIN_CONTROL_TAB,
IP_RW,
ISR_1OFMANY, 0,
132 IUFillSwitch(&CursorMoveSpeedS[USE_GUIDE_SPEED],
"USE_GUIDE_SPEED",
"Guide Speed",
ISS_ON);
133 IUFillSwitch(&CursorMoveSpeedS[USE_CENTERING_SPEED],
"USE_CENTERING_SPEED",
"Centering Speed",
ISS_OFF);
182 return (
const char *)
"iOptron HC8406";
187 const timespec timeout = {0, 50000000L};
192 char initCMD[] =
":V#";
197 int nbytes_written = 0;
199 LOG_DEBUG(
"Initializing iOptron using :V# CMD...");
201 for (
int i = 0; i < 2; i++)
207 nanosleep(&timeout,
nullptr);
215 nanosleep(&timeout,
nullptr);
221 response[nbytes_read] =
'\0';
224 if (!strcmp(response,
"V1.00#"))
228 nanosleep(&timeout,
nullptr);
240 if (!strcmp(name, SyncCMRSP.
name))
251 if (!strcmp(name, CursorMoveSpeedSP.
name))
260 CursorMoveSpeedS[currentSwitch].s =
ISS_ON;
267 if (!strcmp(GuideRateSP.
name, name))
275 CursorMoveSpeedS[USE_GUIDE_SPEED].s =
ISS_ON;
276 CursorMoveSpeedS[USE_CENTERING_SPEED].s =
ISS_OFF;
283 GuideRateS[currentSwitch].s =
ISS_ON;
292 if (!strcmp(CenterRateSP.
name, name))
300 CursorMoveSpeedS[USE_GUIDE_SPEED].s =
ISS_OFF;
301 CursorMoveSpeedS[USE_CENTERING_SPEED].s =
ISS_ON;
308 CenterRateS[currentSwitch].s =
ISS_ON;
344 float tolerance = 1 / 3600.;
359void ioptronHC8406::ioptronHC8406Init()
363 LOG_WARN(
"Sending init CMDs. Unpark, Stop tracking");
367 setioptronHC8406GuideRate(1);
372 const timespec timeout = {0, 100000000L};
376 char RAStr[64], DecStr[64];
380 LOGF_DEBUG(
"<GOTO RA/DEC> %s/%s", RAStr, DecStr);
389 Telescope::AbortSP.apply();
396 Telescope::AbortSP.apply();
411 nanosleep(&timeout,
nullptr);
424 if (slewioptronHC8406() == 0)
427 LOGF_ERROR(
"Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
435 LOGF_DEBUG(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
441 char syncString[256];
449 LOG_ERROR(
"Error setting RA/DEC. Unable to Sync.");
458 case USE_REGULAR_SYNC:
464 if (ioptronHC8406SyncCMR(syncString) < 0)
485 LOGF_DEBUG(
"%s Synchronization successful %s", (syncType == USE_REGULAR_SYNC ?
"CM" :
"CMR"), syncString);
486 LOG_INFO(
"Synchronization successful.");
492int ioptronHC8406::ioptronHC8406SyncCMR(
char *matchedObject)
494 const timespec timeout = {0, 10000000L};
496 int nbytes_write = 0;
507 matchedObject[nbytes_read - 1] =
'\0';
512 nanosleep(&timeout,
nullptr);
514 tcflush(
PortFD, TCIFLUSH);
520int ioptronHC8406::slewioptronHC8406()
525 int nbytes_write = 0, nbytes_read = 0;
541 tcflush(
PortFD, TCIFLUSH);
552 struct ln_zonedate ltm;
557 ln_date_to_zonedate(utc, <m, utc_offset * 3600.0);
559 JD = ln_get_julian_day(utc);
576 if (setioptronHC8406UTCOffset(utc_offset) < 0)
585int ioptronHC8406::setCalenderDate(
int fd,
int dd,
int mm,
int yy)
587 char read_buffer[16];
591 int nbytes_write = 0, nbytes_read = 0;
594 snprintf(read_buffer,
sizeof(read_buffer),
":SC %02d:%02d:%02d#", mm, dd, yy);
598 tcflush(
fd, TCIFLUSH);
606 tcflush(
fd, TCIFLUSH);
614 response[nbytes_read] =
'\0';
618 if (strncmp(response, good_result, strlen(good_result)) == 0)
624 tcflush(
fd, TCIFLUSH);
626 LOGF_DEBUG(
"Set date failed! Response: <%s>", response);
638 double final_longitude;
641 final_longitude = longitude - 360.0;
643 final_longitude = longitude;
645 if (!
isSimulation() && setioptronHC8406Longitude(final_longitude) < 0)
647 LOG_ERROR(
"Error setting site longitude coordinates");
651 if (!
isSimulation() && setioptronHC8406Latitude(latitude) < 0)
653 LOG_ERROR(
"Error setting site latitude coordinates");
659 fs_sexa(L, longitude, 4, 3600);
666int ioptronHC8406::setioptronHC8406Longitude(
double Long)
670 char temp_string[32];
681 snprintf(temp_string,
sizeof(temp_string),
":Sg %c%03d*%02d:%02d#", sign, abs(d), m, s);
683 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
686int ioptronHC8406::setioptronHC8406Latitude(
double Lat)
690 char temp_string[32];
699 snprintf(temp_string,
sizeof(temp_string),
":St %c%02d*%02d:%02d#", sign, abs(d), m, s);
701 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
704int ioptronHC8406::setioptronHC8406UTCOffset(
double hours)
706 char temp_string[16];
708 int h = 0, m = 0, s = 0;
717 snprintf(temp_string,
sizeof(temp_string),
":SG %c%02d#", sign, abs(h));
719 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
722int ioptronHC8406::setioptronHC8406StandardProcedure(
int fd,
const char *data)
724 const timespec timeout = {0, 10000000L};
727 int nbytes_write = 0, nbytes_read = 0;
734 error_type =
tty_read(
fd, bool_return, 1, 5, &nbytes_read);
738 nanosleep(&timeout,
nullptr);
739 tcflush(
fd, TCIFLUSH);
740 nanosleep(&timeout,
nullptr);
749 if (bool_return[0] ==
'0')
764 LOG_WARN(
"<SetTrackEnabled> START TRACKING AT SIDEREAL SPEED (:RT2#)");
765 return setioptronHC8406TrackMode(0);
769 LOG_WARN(
"<SetTrackEnabled> STOP TRACKING (:RT9#)");
770 return setioptronHC8406TrackMode(3);
776 return (setioptronHC8406TrackMode(mode));
779int ioptronHC8406::setioptronHC8406TrackMode(
int mode)
785 int nbytes_write = 0 ;
805 snprintf(
cmd, 8,
":RT%d#", mmode);
820 int nbytes_write = 0;
824 tcflush(
PortFD, TCIFLUSH);
828 LOG_INFO(
"Parking is in progress...");
841 const timespec timeout = {1, 0L};
860 LOG_WARN(
"<ReadScopeStatus> SLEWING");
863 LOG_WARN(
"<ReadScopeStatus> TRACKING");
866 LOG_WARN(
"<ReadScopeStatus> PARKING");
869 LOG_WARN(
"<ReadScopeStatus> PARKED");
872 LOG_WARN(
"<ReadScopeStatus> UNDEFINED");
881 nanosleep(&timeout,
nullptr);
891 LOG_WARN(
"Slew is complete. TRACKING");
922void ioptronHC8406::mountSim()
924 static struct timeval ltv;
930 gettimeofday(&tv,
nullptr);
932 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
935 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
994int ioptronHC8406::setioptronHC8406GuideRate(
int rate)
996 return setMoveRate(rate, USE_GUIDE_SPEED);
999int ioptronHC8406::setioptronHC8406CenterRate(
int rate)
1001 return setMoveRate(rate, USE_CENTERING_SPEED);
1004int ioptronHC8406::setioptronHC8406SlewRate(
int rate)
1006 return setMoveRate(rate, USE_SLEW_SPEED);
1009int ioptronHC8406::setioptronHC8406CursorMoveSpeed(
int type)
1011 return setMoveRate(-1,
type);
1014int ioptronHC8406::setMoveRate(
int rate,
int move_type)
1019 int nbytes_written = 0;
1030 case USE_GUIDE_SPEED:
1031 snprintf(
cmd, 16,
":RG%0d#", rate);
1033 case USE_CENTERING_SPEED:
1034 snprintf(
cmd, 16,
":RC%0d#", rate);
1036 case USE_SLEW_SPEED:
1037 snprintf(
cmd, 16,
":RS%0d#", rate);
1048 case USE_GUIDE_SPEED:
1049 snprintf(
cmd, 16,
":RG#");
1051 case USE_CENTERING_SPEED:
1052 snprintf(
cmd, 16,
":RC#");
1054 case USE_SLEW_SPEED:
1055 snprintf(
cmd, 16,
":RS#");
1065 tcflush(
PortFD, TCIFLUSH);
1078void ioptronHC8406::syncSideOfPier()
1080 const char *
cmd =
":pS#";
1082 char response[16] = { 0 };
1083 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1087 tcflush(
PortFD, TCIOFLUSH);
1093 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1102 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1106 response[nbytes_read - 1] =
'\0';
1108 tcflush(
PortFD, TCIOFLUSH);
1112 if (!strcmp(response,
"East"))
1128int ioptronHC8406::getCommandString(
int fd,
char *data,
const char *
cmd)
1132 int nbytes_write = 0, nbytes_read = 0;
1139 tcflush(
fd, TCIFLUSH);
1141 if (error_type !=
TTY_OK)
1144 term = strchr(data,
'#');
1156 char cdate[32] = {0};
1159 int utc_h, utc_m, utc_s;
1160 double lx200_utc_offset = 0;
1161 char utc_offset_res[32] = {0};
1162 int day, month, year, result;
1166 memset(<m, 0,
sizeof(ltm));
1167 memset(&utm, 0,
sizeof(utm));
1173 snprintf(cdate, 32,
"%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
1174 IDLog(
"Telescope ISO date and time: %s\n", cdate);
1186 f_scansexa(utc_offset_res, &lx200_utc_offset);
1187 result = sscanf(utc_offset_res,
"%d%*c%d%*c%d", &utc_h, &utc_m, &utc_s);
1190 LOG_ERROR(
"Error reading UTC offset from Telescope.");
1193 LOGF_DEBUG(
"<VAL> UTC offset: %d:%d:%d --->%g", utc_h, utc_m, utc_s, lx200_utc_offset);
1195 LOGF_DEBUG(
"<VAL> UTC offset str: %s", utc_offset_res);
1203 result = sscanf(cdate,
"%d%*c%d%*c%d", &year, &month, &day);
1206 LOG_ERROR(
"Error reading date from Telescope.");
1215 ltm.tm_mon = month - 1;
1216 ltm.tm_year = year - 1900;
1220 time_epoch = mktime(<m);
1224 time_epoch -= (int)(lx200_utc_offset * 3600.0);
1227 localtime_r(&time_epoch, &utm);
1230 strftime(cdate, 32,
"%Y-%m-%dT%H:%M:%S", &utm);
1233 LOGF_DEBUG(
"Mount controller Local Time: %02d:%02d:%02d", h, m, s);
1244 const timespec timeout = {1, 0L};
1245 int rc = 0, nbytes_written = 0;
1247 uint32_t duration_left = 0, duration_now = duration_msec;
1248 if (duration_msec > 999)
1251 duration_left = duration_msec - duration_now;
1256 LOGF_DEBUG(
"Pulse %d <999 Sent only one", duration_msec);
1262 sprintf(
cmd,
":Mn%03d#", duration_now);
1265 sprintf(
cmd,
":Ms%03d#", duration_now);
1268 sprintf(
cmd,
":Me%03d#", duration_now);
1271 sprintf(
cmd,
":Mw%03d#", duration_now);
1282 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1285 tcflush(
PortFD, TCIFLUSH);
1287 if (duration_left != 0)
1289 LOGF_DEBUG(
"pulse guide. Pulse >999. ms left:%d", duration_left);
1290 nanosleep(&timeout,
nullptr);
INDI::PropertyText getText(const char *name) 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
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isSwitchOn(const std::string &name) const
TelescopeStatus TrackState
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
virtual bool initProperties() override
Called to initialize basic properties required all the time.
@ LX200_HAS_PULSE_GUIDING
virtual void slewError(int slewCode)
virtual bool sendScopeLocation()
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void setLX200Capability(uint32_t cap)
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool sendScopeTime() override
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual const char * getDefaultName() override
virtual bool Park() override
Park the telescope to its home position.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool checkConnection() override
virtual int SendPulseCmd(int8_t direction, uint32_t duration_msec) override
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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 saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool isSlewComplete() override
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void getBasicData() override
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual bool ReadScopeStatus() override
Read telescope status.
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::PropertySwitch AbortSP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertySwitch TrackModeSP
INDI::PropertyText TimeTP
INDI::PropertySwitch MovementWESP
INDI::PropertySwitch CoordSP
#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 f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
void IDLog(const char *fmt,...)
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 IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
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 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.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void IDMessage(const char *dev, const char *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,...)
#define ioptronHC8406_TIMEOUT
#define ioptronHC8406_CALDATE_RESULT
int setObjectRA(int fd, double ra, bool addSpace)
int setObjectDEC(int fd, double dec, bool addSpace)
int checkLX200EquatorialFormat(int fd)
int setCalenderDate(int fd, int dd, int mm, int yy, bool addSpace)
int getCalendarDate(int fd, char *date)
int getCommandString(int fd, char *data, const char *cmd)
#define getLX200DEC(fd, x)
#define getLX200RA(fd, x)
#define getLocalTime24(fd, x)