33 #include <libnova/julian_day.h>
34 #include <libnova/sidereal_time.h>
41 #include <sys/ioctl.h>
46 #define PMC8_TIMEOUT 5
48 #define PMC8_SIMUL_VERSION_RESP "ESGvES06B9T9"
51 #define PMC8_G11_AXIS0_SCALE 4608000.0
52 #define PMC8_G11_AXIS1_SCALE 4608000.0
54 #define PMC8_EXOS2_AXIS0_SCALE 4147200.0
55 #define PMC8_EXOS2_AXIS1_SCALE 4147200.0
57 #define PMC8_iEXOS100_AXIS0_SCALE 4147200.0
58 #define PMC8_iEXOS100_AXIS1_SCALE 4147200.0
64 #define ARCSEC_IN_CIRCLE 1296000.0
68 #define PMC8_MAX_PRECISE_MOTOR_RATE 62500
71 #define PMC8_PULSE_GUIDE_MIN_MS 20
74 #define PMC8_PULSE_GUIDE_MAX_NOTIMER 250
76 #define PMC8_MAX_RETRIES 3
77 #define PMC8_RETRY_DELAY 30000
78 #define PMC8_MAX_IO_ERROR_THRESHOLD 2
80 #define PMC8_RATE_SIDEREAL 15.000
81 #define PMC8_RATE_LUNAR 14.451
82 #define PMC8_RATE_SOLAR 14.959
83 #define PMC8_RATE_KING 14.996
144 sprintf(h,
"%08X", tmp);
185 float capped_move_rate = rate;
308 "Connecting to PMC8 via standard Serial cable. Please wait 15 seconds for mount to reset.");
310 "Connecting to PMC8 via Serial. Autodecting cable type. This could take up to 30 seconds.");
316 for (
int i = 0; i < 2; i++)
330 int serial = TIOCM_DTR;
331 ioctl(
fd, TIOCMBIC, &serial);
334 for (
int i = 0; i < 2; i++)
341 "Your mount will reset and lose its position anytime you disconnect and reconnect."
342 "See http://indilib.org/devices/telescopes/explore-scientific-g11-pmc-eight/ ");
350 "check_pmc8_connection(): Error connecting. Check power and connection settings.");
357 char initCMD[] =
"ESGv!";
362 int nbytes_written = 0;
367 nbytes_read = strlen(response);
387 return (!strncmp(response,
"ESGvES", 6));
393 info->
Model.assign(
"PMC-Eight");
417 char cmd[] =
"ESGi!";
422 int nbytes_written = 0;
427 nbytes_read = strlen(response);
445 if (nbytes_read >= 31)
448 char num_str[3] = {0};
449 strncat(num_str, response + 20, 2);
450 int p9 = (int)strtol(num_str,
nullptr, 10);
473 "Could not detect device type. Only received #%d bytes, expected at least 31.", nbytes_read);
477 tcflush(
fd, TCIFLUSH);
487 char cmd[] =
"ESGv!";
493 int nbytes_written = 0;
498 nbytes_read = strlen(response);
518 if (nbytes_read >= 12)
522 strncpy(board, response + 6, nbytes_read - 7);
528 tcflush(
fd, TCIFLUSH);
534 "Could not read firmware. Only received #%d bytes, expected at least 12.", nbytes_read);
560 int nbytes_written = 0;
562 snprintf(
cmd,
sizeof(
cmd),
"ESGr%d!", axis);
591 if (nbytes_read != 10)
597 char num_str[16] = {0};
599 strcpy(num_str,
"0X");
600 strncat(num_str, response + 5, 6);
602 int mrate = (int)strtol(num_str,
nullptr, 0);
616 int nbytes_written = 0;
618 snprintf(
cmd,
sizeof(
cmd),
"ESGd%d!", axis);
647 if (nbytes_read != 7)
653 char num_str[16] = {0};
655 strncat(num_str, response + 5, 2);
657 dir = (int)strtol(num_str,
nullptr, 0);
668 char cmd[32], expresp[32];
673 int nbytes_written = 0;
675 snprintf(
cmd,
sizeof(
cmd),
"ESSd%d%d!", axis, dir);
701 snprintf(expresp,
sizeof(expresp),
"ESGd%d%d!", axis, dir);
794 int nbytes_written = 0;
796 snprintf(
cmd,
sizeof(
cmd),
"ESGx!");
817 if (nbytes_read != 9)
823 char num_str[16] = {0};
825 strcpy(num_str,
"0X");
826 strncat(num_str, response + 4, 4);
828 int mrate = (int)strtol(num_str,
nullptr, 0);
844 int tmotor, refmotor;
891 int nbytes_written = 0;
893 snprintf(
cmd,
sizeof(
cmd),
"ESSr%d%04X!", axis, mrate);
912 snprintf(
cmd,
sizeof(
cmd),
"ESGr%d", axis);
920 if (nbytes_read == 10)
922 tcflush(
fd, TCIFLUSH);
964 bool set_pmc8_track_enabled(
int fd,
bool enabled)
971 int nbytes_written = 0;
973 snprintf(
cmd, 32,
":ST%d#", enabled ? 1 : 0);
1028 if (rate < 0) direction = !direction;
1044 int nbytes_read = 0;
1045 int nbytes_written = 0;
1054 snprintf(
cmd,
sizeof(
cmd),
"ESTr%04X!", rateval);
1077 if (nbytes_read != 9)
1083 tcflush(
fd, TCIFLUSH);
1182 char cmd[32], expresp[32];
1186 int nbytes_read = 0;
1187 int nbytes_written = 0;
1189 snprintf(
cmd,
sizeof(
cmd),
"ESSf%d%02X!", axis,
int(rate * 100));
1198 snprintf(expresp,
sizeof(expresp),
"ESGf%d%02X!", axis,
int(rate * 100));
1224 int nbytes_read = 0;
1225 int nbytes_written = 0;
1227 snprintf(
cmd,
sizeof(
cmd),
"ESGf%d!", axis);
1244 if (nbytes_read != 8)
1250 char num_str[16] = {0};
1252 strcpy(num_str,
"0X");
1253 strncat(num_str, response + 5, 2);
1254 int tint = strtol(num_str,
nullptr, 0);
1256 rate = ((double)tint) / 100;
1299 double cur_rate = 0;
1304 long long pulse_start_us;
1305 long long pulse_sofar_us;
1326 timetaken_us = ms * 1000;
1347 cur_rate = ratehint;
1353 cur_rate = ratehint;
1361 "pmc8_start_guide(): Cannot send guide correction while slewing! rate=%d dir=%d",
1366 double new_rate = cur_rate;
1380 "pmc8_start_guide(): with current tracking rate of %f, requested guide rate of %f would flip RA motor in opposite direction, so pausing motor instead.",
1381 cur_rate, new_rate);
1386 gettimeofday(&tp,
nullptr);
1387 pulse_start_us = tp.tv_sec * 1000000 + tp.tv_usec;
1404 if (new_rate < 0) new_dir = 1;
1419 if (cur_dir != new_dir)
1424 gettimeofday(&tp,
nullptr);
1425 pulse_start_us = tp.tv_sec * 1000000 + tp.tv_usec;
1448 gettimeofday(&tp,
nullptr);
1449 pulse_sofar_us = (tp.tv_sec * 1000000 + tp.tv_usec) - pulse_start_us;
1451 timetaken_us = pulse_sofar_us;
1461 long long pulse_end_us;
1479 tcflush(
fd, TCIFLUSH);
1490 gettimeofday(&tp,
nullptr);
1491 pulse_end_us = tp.tv_sec * 1000000 + tp.tv_usec;
1530 tcflush(
fd, TCIFLUSH);
1543 if (axispos > 8388608)
1544 r = 0 - (16777216 - axispos);
1561 hour_angle = lst -
ra;
1564 if (hour_angle > 12)
1565 hour_angle = hour_angle - 24;
1566 else if (hour_angle <= -12)
1567 hour_angle = hour_angle + 24;
1573 motor_angle = hour_angle - 6;
1575 motor_angle = hour_angle + 6;
1583 motor_angle = -(hour_angle + 6);
1585 motor_angle = -(hour_angle - 6);
1620 hour_angle = motor_angle + 6;
1622 hour_angle = motor_angle - 6;
1628 hour_angle = -(motor_angle + 6);
1630 hour_angle = -(motor_angle - 6);
1635 ra_value = lst - hour_angle;
1639 if (ra_value >= 24.0)
1640 ra_value = ra_value - 24.0;
1641 else if (ra_value < 0.0)
1642 ra_value = ra_value + 24.0;
1651 if (motor_angle >= 0)
1652 dec_value = 90 - motor_angle;
1654 dec_value = 90 + motor_angle;
1659 if (motor_angle >= 0)
1660 dec_value = -90 + motor_angle;
1662 dec_value = -90 - motor_angle;
1676 motor_angle = (
dec - 90.0);
1678 motor_angle = -(
dec - 90.0);
1686 motor_angle = -(
dec + 90.0);
1688 motor_angle = (
dec + 90.0);
1710 int nbytes_read = 0;
1711 int nbytes_written = 0;
1718 snprintf(
cmd,
sizeof(
cmd),
"ESPt%d%s!", naxis, hexpt);
1730 snprintf(expresp,
sizeof(expresp),
"ESGt%d%s!", naxis, hexpt);
1767 int nbytes_read = 0;
1768 int nbytes_written = 0;
1777 snprintf(
cmd,
sizeof(
cmd),
"ESSp%d%s!", axis, hexpt);
1786 snprintf(expresp,
sizeof(expresp),
"ESGp%d%s!", axis, hexpt);
1821 int nbytes_read = 0;
1822 int nbytes_written = 0;
1830 snprintf(
cmd,
sizeof(
cmd),
"ESGp%d!", axis);
1847 if (nbytes_read != 12)
1853 char num_str[16] = {0};
1855 strcpy(num_str,
"0X");
1856 strncat(num_str, response + 5, 6);
1858 point = (int)strtol(num_str,
nullptr, 0);
1867 int axis_ra_pos, axis_dec_pos;
1958 int nbytes_read = 0;
1959 int nbytes_written = 0;
1961 snprintf(
cmd,
sizeof(
cmd),
"ESPt300000!");
1973 snprintf(expresp,
sizeof(expresp),
"ESGt3!");
1990 int racounts, deccounts;
2036 hour_angle = lst -
ra;
2039 if (hour_angle > 12)
2040 hour_angle = hour_angle - 24;
2041 else if (hour_angle <= -12)
2042 hour_angle = hour_angle + 24;
2047 if (hour_angle < 0.0)
2055 if (hour_angle < 0.0)
2065 int racounts, deccounts;
2111 int racounts, deccounts;
2156 int racounts, deccounts;
2215 if (strstr(errmsg,
"Connection timed out") || strstr(errmsg,
"Bad"))
2221 if (*nbytes_read > 0)
2223 buf[*nbytes_read] =
'\0';
2233 strcpy(buf, buf + 7);
2234 *nbytes_read = *nbytes_read - 7;
2237 if (strncmp(buf,
"AT", 2) == 0)
2239 strcpy(buf, buf + 2);
2240 *nbytes_read = *nbytes_read - 2;
2243 if (strncmp(buf,
"ESGp!", 5) == 0)
2252 if (strncmp(buf, expected, strlen(expected)) != 0)
2289 tcflush(
fd, TCIFLUSH);
2293 if ((err_code =
tty_write(
fd, buf, nbytes, nbytes_written)))
2297 if (strstr(errmsg,
"Broken pipe") || strstr(errmsg,
"Bad"))
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 tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
#define DEBUGDEVICE(device, priority, msg)
#define DEBUGFDEVICE(device, priority, msg,...)
bool convert_motor_rate_to_move_rate(int mrate, double *rate)
bool get_pmc8_model(int fd, FirmwareInfo *info)
bool get_pmc8_guide_rate(int fd, PMC8_AXIS axis, double &rate)
PulseGuideState NS_PulseGuideState
void set_pmc8_location(double latitude, double longitude)
#define PMC8_MAX_IO_ERROR_THRESHOLD
#define PMC8_iEXOS100_AXIS0_SCALE
bool set_pmc8_custom_ra_track_rate(int fd, double rate)
#define PMC8_RATE_SIDEREAL
uint8_t get_pmc8_tracking_mode_from_rate(double rate)
double pmc8_sidereal_rate_fraction_ra
bool start_pmc8_guide(int fd, PMC8_DIRECTION gdir, int ms, long &timetaken_us, double ratehint)
bool set_pmc8_target_position_axis(int fd, PMC8_AXIS axis, int point)
#define PMC8_SIMUL_VERSION_RESP
void set_pmc8_sim_system_status(PMC8_SYSTEM_STATUS value)
bool set_pmc8_custom_dec_track_rate(int fd, double rate)
bool convert_precise_motor_to_rate(int mrate, double *rate)
void set_pmc8_device(const char *name)
bool set_pmc8_axis_move_rate(int fd, PMC8_AXIS axis, float rate)
#define PMC8_EXOS2_AXIS0_SCALE
bool stop_pmc8_guide(int fd, PMC8_DIRECTION gdir)
void set_pmc8_debug(bool enable)
bool sync_pmc8(int fd, double ra, double dec)
void convert_motor_counts_to_hex(int val, char *hex)
bool abort_pmc8_goto(int fd)
double pmc8_sidereal_rate_fraction_de
bool convert_precise_rate_to_motor(double rate, int *mrate)
int convert_axispos_to_motor(int axispos)
bool slew_pmc8(int fd, double ra, double dec)
#define PMC8_PULSE_GUIDE_MIN_MS
bool convert_ra_to_motor(double ra, INDI::Telescope::TelescopePierSide sop, int *mcounts)
bool get_pmc8_response(int fd, char *buf, int *nbytes_read, const char *expected=NULL)
#define PMC8_EXOS2_AXIS1_SCALE
bool get_pmc8_is_scope_slewing(int fd, bool &isslew)
PulseGuideState EW_PulseGuideState
bool send_pmc8_command(int fd, const char *buf, int nbytes, int *nbytes_written)
bool set_pmc8_track_mode(int fd, uint8_t mode)
bool convert_dec_to_motor(double dec, INDI::Telescope::TelescopePierSide sop, int *mcounts)
char pmc8_device[MAXINDIDEVICE]
bool get_pmc8_position_axis(int fd, PMC8_AXIS axis, int &point)
bool convert_move_rate_to_motor(float rate, int *mrate)
#define PMC8_iEXOS100_AXIS1_SCALE
bool set_pmc8_radec(int fd, double ra, double dec)
bool pmc8_isRev2Compliant
bool set_pmc8_target_position(int fd, int rapoint, int decpoint)
void set_pmc8_mountParameters(int index)
bool set_pmc8_guide_rate(int fd, PMC8_AXIS axis, double rate)
INDI::Telescope::TelescopePierSide destSideOfPier(double ra, double dec)
#define PMC8_G11_AXIS0_SCALE
bool set_pmc8_axis_motor_rate(int fd, PMC8_AXIS axis, int mrate, bool fast)
void set_pmc8_simulation(bool enable)
#define PMC8_G11_AXIS1_SCALE
void set_pmc8_goto_resume(bool resume)
bool get_pmc8_firmware(int fd, FirmwareInfo *info)
bool get_pmc8_main_firmware(int fd, FirmwareInfo *info)
bool get_pmc8_coords(int fd, double &ra, double &dec)
bool set_pmc8_position(int fd, int rapoint, int decpoint)
bool set_pmc8_custom_ra_move_rate(int fd, double rate)
bool get_pmc8_reconnect_flag()
bool get_pmc8_guide_state(PMC8_DIRECTION gdir, PulseGuideState **pstate)
PMC8_CONNECTION_TYPE pmc8_connection
bool get_pmc8_tracking_data(int fd, double &rate, uint8_t &mode)
bool check_pmc8_connection(int fd, PMC8_CONNECTION_TYPE connection)
bool convert_motor_to_radec(int racounts, int deccounts, double &ra_value, double &dec_value)
bool set_pmc8_custom_dec_move_rate(int fd, double rate)
bool set_pmc8_direction_axis(int fd, PMC8_AXIS axis, int dir, bool fast)
void set_pmc8_sim_move_rate(int value)
bool set_pmc8_position_axis(int fd, PMC8_AXIS axis, int point)
bool stop_pmc8_tracking_motion(int fd)
void set_pmc8_sim_track_rate(PMC8_TRACK_RATE value)
bool get_pmc8_direction_axis(int fd, PMC8_AXIS axis, int &dir)
bool get_pmc8_position(int fd, int &rapoint, int &decpoint)
void set_pmc8_sim_ra(double ra)
void set_pmc8_reconnect_flag()
bool set_pmc8_ra_tracking(int fd, double rate)
struct PulseGuideState PulseGuideState
void set_pmc8_sim_dec(double dec)
bool set_pmc8_move_rate_axis(int fd, PMC8_DIRECTION dir, int reqrate)
#define PMC8_MAX_PRECISE_MOTOR_RATE
bool get_pmc8_track_rate(int fd, double &rate)
bool get_pmc8_move_rate_axis(int fd, PMC8_AXIS axis, double &rate)
#define PMC8_MAX_MOVE_RATE
#define PMC8_MAX_TRACK_RATE
PMC8_MOUNT_TYPES MountType
std::string MainBoardFirmware
PMC8_SYSTEM_STATUS systemStatus
double round(double value, int decimal_places)