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.;
359 void 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);
409 nanosleep(&timeout,
nullptr);
421 if (slewioptronHC8406() == 0)
424 IDSetNumber(&
EqNP,
"Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
431 LOGF_DEBUG(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
437 char syncString[256];
453 case USE_REGULAR_SYNC:
459 if (ioptronHC8406SyncCMR(syncString) < 0)
479 LOGF_DEBUG(
"%s Synchronization successful %s", (syncType == USE_REGULAR_SYNC ?
"CM" :
"CMR"), syncString);
480 LOG_INFO(
"Synchronization successful.");
486 int ioptronHC8406::ioptronHC8406SyncCMR(
char *matchedObject)
488 const timespec timeout = {0, 10000000L};
490 int nbytes_write = 0;
501 matchedObject[nbytes_read - 1] =
'\0';
506 nanosleep(&timeout,
nullptr);
508 tcflush(
PortFD, TCIFLUSH);
514 int ioptronHC8406::slewioptronHC8406()
519 int nbytes_write = 0, nbytes_read = 0;
535 tcflush(
PortFD, TCIFLUSH);
546 struct ln_zonedate ltm;
551 ln_date_to_zonedate(utc, <m, utc_offset * 3600.0);
553 JD = ln_get_julian_day(utc);
570 if (setioptronHC8406UTCOffset(utc_offset) < 0)
579 int ioptronHC8406::setCalenderDate(
int fd,
int dd,
int mm,
int yy)
581 char read_buffer[16];
585 int nbytes_write = 0, nbytes_read = 0;
588 snprintf(read_buffer,
sizeof(read_buffer),
":SC %02d:%02d:%02d#", mm, dd, yy);
592 tcflush(
fd, TCIFLUSH);
600 tcflush(
fd, TCIFLUSH);
608 response[nbytes_read] =
'\0';
612 if (strncmp(response, good_result, strlen(good_result)) == 0)
618 tcflush(
fd, TCIFLUSH);
620 LOGF_DEBUG(
"Set date failed! Response: <%s>", response);
632 double final_longitude;
635 final_longitude = longitude - 360.0;
637 final_longitude = longitude;
639 if (!
isSimulation() && setioptronHC8406Longitude(final_longitude) < 0)
641 LOG_ERROR(
"Error setting site longitude coordinates");
645 if (!
isSimulation() && setioptronHC8406Latitude(latitude) < 0)
647 LOG_ERROR(
"Error setting site latitude coordinates");
653 fs_sexa(L, longitude, 4, 3600);
660 int ioptronHC8406::setioptronHC8406Longitude(
double Long)
664 char temp_string[32];
675 snprintf(temp_string,
sizeof(temp_string),
":Sg %c%03d*%02d:%02d#", sign, abs(d), m, s);
677 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
680 int ioptronHC8406::setioptronHC8406Latitude(
double Lat)
684 char temp_string[32];
693 snprintf(temp_string,
sizeof(temp_string),
":St %c%02d*%02d:%02d#", sign, abs(d), m, s);
695 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
698 int ioptronHC8406::setioptronHC8406UTCOffset(
double hours)
700 char temp_string[16];
702 int h = 0, m = 0, s = 0;
711 snprintf(temp_string,
sizeof(temp_string),
":SG %c%02d#", sign, abs(h));
713 return (setioptronHC8406StandardProcedure(
PortFD, temp_string));
716 int ioptronHC8406::setioptronHC8406StandardProcedure(
int fd,
const char *data)
718 const timespec timeout = {0, 10000000L};
721 int nbytes_write = 0, nbytes_read = 0;
728 error_type =
tty_read(
fd, bool_return, 1, 5, &nbytes_read);
732 nanosleep(&timeout,
nullptr);
733 tcflush(
fd, TCIFLUSH);
734 nanosleep(&timeout,
nullptr);
743 if (bool_return[0] ==
'0')
758 LOG_WARN(
"<SetTrackEnabled> START TRACKING AT SIDERAL SPEED (:RT2#)");
759 return setioptronHC8406TrackMode(0);
763 LOG_WARN(
"<SetTrackEnabled> STOP TRACKING (:RT9#)");
764 return setioptronHC8406TrackMode(3);
770 return (setioptronHC8406TrackMode(mode));
773 int ioptronHC8406::setioptronHC8406TrackMode(
int mode)
779 int nbytes_write = 0 ;
799 snprintf(
cmd, 8,
":RT%d#", mmode);
814 int nbytes_write = 0;
818 tcflush(
PortFD, TCIFLUSH);
822 LOG_INFO(
"Parking is in progress...");
835 const timespec timeout = {1, 0L};
854 LOG_WARN(
"<ReadScopeStatus> SLEWING");
857 LOG_WARN(
"<ReadScopeStatus> TRACKING");
860 LOG_WARN(
"<ReadScopeStatus> PARKING");
863 LOG_WARN(
"<ReadScopeStatus> PARKED");
866 LOG_WARN(
"<ReadScopeStatus> UNDEFINED");
875 nanosleep(&timeout,
nullptr);
885 LOG_WARN(
"Slew is complete. TRACKING");
915 void ioptronHC8406::mountSim()
917 static struct timeval ltv;
923 gettimeofday(&tv,
nullptr);
925 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
928 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
987 int ioptronHC8406::setioptronHC8406GuideRate(
int rate)
989 return setMoveRate(rate, USE_GUIDE_SPEED);
992 int ioptronHC8406::setioptronHC8406CenterRate(
int rate)
994 return setMoveRate(rate, USE_CENTERING_SPEED);
997 int ioptronHC8406::setioptronHC8406SlewRate(
int rate)
999 return setMoveRate(rate, USE_SLEW_SPEED);
1002 int ioptronHC8406::setioptronHC8406CursorMoveSpeed(
int type)
1004 return setMoveRate(-1,
type);
1007 int ioptronHC8406::setMoveRate(
int rate,
int move_type)
1012 int nbytes_written = 0;
1023 case USE_GUIDE_SPEED:
1024 snprintf(
cmd, 16,
":RG%0d#", rate);
1026 case USE_CENTERING_SPEED:
1027 snprintf(
cmd, 16,
":RC%0d#", rate);
1029 case USE_SLEW_SPEED:
1030 snprintf(
cmd, 16,
":RS%0d#", rate);
1041 case USE_GUIDE_SPEED:
1042 snprintf(
cmd, 16,
":RG#");
1044 case USE_CENTERING_SPEED:
1045 snprintf(
cmd, 16,
":RC#");
1047 case USE_SLEW_SPEED:
1048 snprintf(
cmd, 16,
":RS#");
1058 tcflush(
PortFD, TCIFLUSH);
1071 void ioptronHC8406::syncSideOfPier()
1073 const char *
cmd =
":pS#";
1075 char response[16] = { 0 };
1076 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1080 tcflush(
PortFD, TCIOFLUSH);
1086 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1095 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1099 response[nbytes_read - 1] =
'\0';
1101 tcflush(
PortFD, TCIOFLUSH);
1105 if (!strcmp(response,
"East"))
1121 int ioptronHC8406::getCommandString(
int fd,
char *data,
const char *
cmd)
1125 int nbytes_write = 0, nbytes_read = 0;
1132 tcflush(
fd, TCIFLUSH);
1134 if (error_type !=
TTY_OK)
1137 term = strchr(data,
'#');
1149 char cdate[32] = {0};
1152 int utc_h, utc_m, utc_s;
1153 double lx200_utc_offset = 0;
1154 char utc_offset_res[32] = {0};
1155 int day, month, year, result;
1159 memset(<m, 0,
sizeof(ltm));
1160 memset(&utm, 0,
sizeof(utm));
1166 snprintf(cdate, 32,
"%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
1167 IDLog(
"Telescope ISO date and time: %s\n", cdate);
1179 f_scansexa(utc_offset_res, &lx200_utc_offset);
1180 result = sscanf(utc_offset_res,
"%d%*c%d%*c%d", &utc_h, &utc_m, &utc_s);
1183 LOG_ERROR(
"Error reading UTC offset from Telescope.");
1186 LOGF_DEBUG(
"<VAL> UTC offset: %d:%d:%d --->%g", utc_h, utc_m, utc_s, lx200_utc_offset);
1188 LOGF_DEBUG(
"<VAL> UTC offset str: %s", utc_offset_res);
1196 result = sscanf(cdate,
"%d%*c%d%*c%d", &year, &month, &day);
1199 LOG_ERROR(
"Error reading date from Telescope.");
1208 ltm.tm_mon = month - 1;
1209 ltm.tm_year = year - 1900;
1213 time_epoch = mktime(<m);
1217 time_epoch -= (int)(lx200_utc_offset * 3600.0);
1220 localtime_r(&time_epoch, &utm);
1223 strftime(cdate, 32,
"%Y-%m-%dT%H:%M:%S", &utm);
1226 LOGF_DEBUG(
"Mount controller Local Time: %02d:%02d:%02d", h, m, s);
1237 const timespec timeout = {1, 0L};
1238 int rc = 0, nbytes_written = 0;
1240 uint32_t duration_left = 0, duration_now = duration_msec;
1241 if (duration_msec > 999)
1244 duration_left = duration_msec - duration_now;
1249 LOGF_DEBUG(
"Pulse %d <999 Sent only one", duration_msec);
1255 sprintf(
cmd,
":Mn%03d#", duration_now);
1258 sprintf(
cmd,
":Ms%03d#", duration_now);
1261 sprintf(
cmd,
":Me%03d#", duration_now);
1264 sprintf(
cmd,
":Mw%03d#", duration_now);
1275 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1278 tcflush(
PortFD, TCIFLUSH);
1280 if (duration_left != 0)
1282 LOGF_DEBUG(
"pulse guide. Pulse >999. ms left:%d", duration_left);
1283 nanosleep(&timeout,
nullptr);
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
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
ITextVectorProperty TimeTP
ISwitchVectorProperty CoordSP
ISwitchVectorProperty TrackModeSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
@ 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)
ISwitchVectorProperty MovementWESP
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void slewError(int slewCode)
@ LX200_HAS_PULSE_GUIDING
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.
#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 IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
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,...)
void IDMessage(const char *dev, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, 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)