34#include <libnova/julian_day.h>
35#include <libnova/sidereal_time.h>
49#define PMC8_SIMUL_VERSION_RESP "ESGvES06B9T9"
52#define PMC8_G11_AXIS0_SCALE 4608000.0
53#define PMC8_G11_AXIS1_SCALE 4608000.0
55#define PMC8_EXOS2_AXIS0_SCALE 4147200.0
56#define PMC8_EXOS2_AXIS1_SCALE 4147200.0
58#define PMC8_iEXOS100_AXIS0_SCALE 4147200.0
59#define PMC8_iEXOS100_AXIS1_SCALE 4147200.0
65#define ARCSEC_IN_CIRCLE 1296000.0
69#define PMC8_MAX_PRECISE_MOTOR_RATE 62500
72#define PMC8_PULSE_GUIDE_MIN_MS 20
75#define PMC8_PULSE_GUIDE_MAX_NOTIMER 250
77#define PMC8_MAX_RETRIES 3
78#define PMC8_RETRY_DELAY 30000
79#define PMC8_MAX_IO_ERROR_THRESHOLD 2
87#define PMC8_RATE_SIDEREAL 15.000
88#define PMC8_RATE_LUNAR 14.451
89#define PMC8_RATE_SOLAR 14.959
90#define PMC8_RATE_KING 14.996
151 sprintf(h,
"%08X", tmp);
192 float capped_move_rate = rate;
315 "Connecting to PMC8 via standard Serial cable. Please wait 15 seconds for mount to reset.");
317 "Connecting to PMC8 via Serial. Autodecting cable type. This could take up to 30 seconds.");
323 for (
int i = 0; i < 2; i++)
337 int serial = TIOCM_DTR;
338 ioctl(
fd, TIOCMBIC, &serial);
341 for (
int i = 0; i < 2; i++)
348 "Your mount will reset and lose its position anytime you disconnect and reconnect."
349 "See http://indilib.org/devices/telescopes/explore-scientific-g11-pmc-eight/ ");
357 "check_pmc8_connection(): Error connecting. Check power and connection settings.");
364 char initCMD[] =
"ESGv!";
369 int nbytes_written = 0;
374 nbytes_read = strlen(response);
394 return (!strncmp(response,
"ESGvES", 6));
400 info->
Model.assign(
"PMC-Eight");
424 char cmd[] =
"ESGi!";
429 int nbytes_written = 0;
434 nbytes_read = strlen(response);
452 if (nbytes_read >= 31)
455 char num_str[3] = {0};
456 snprintf(num_str,
sizeof(num_str),
"%.2s", response + 20);
457 int p9 = (int)strtol(num_str,
nullptr, 10);
480 "Could not detect device type. Only received #%d bytes, expected at least 31.", nbytes_read);
484 tcflush(
fd, TCIFLUSH);
494 char cmd[] =
"ESGv!";
500 int nbytes_written = 0;
505 nbytes_read = strlen(response);
525 if (nbytes_read >= 12)
529 strncpy(board, response + 6, nbytes_read - 7);
535 tcflush(
fd, TCIFLUSH);
541 "Could not read firmware. Only received #%d bytes, expected at least 12.", nbytes_read);
567 int nbytes_written = 0;
569 snprintf(
cmd,
sizeof(
cmd),
"ESGr%d!", axis);
598 if (nbytes_read != 10)
604 char num_str[16] = {0};
606 snprintf(num_str,
sizeof(num_str),
"0X%.6s", response + 5);
608 int mrate = (int)strtol(num_str,
nullptr, 0);
622 int nbytes_written = 0;
624 snprintf(
cmd,
sizeof(
cmd),
"ESGd%d!", axis);
653 if (nbytes_read != 7)
659 char num_str[16] = {0};
661 snprintf(num_str,
sizeof(num_str),
"%.2s", response + 5);
663 dir = (int)strtol(num_str,
nullptr, 0);
674 char cmd[32], expresp[32];
679 int nbytes_written = 0;
681 snprintf(
cmd,
sizeof(
cmd),
"ESSd%d%d!", axis, dir);
707 snprintf(expresp,
sizeof(expresp),
"ESGd%d%d!", axis, dir);
809 int nbytes_written = 0;
811 snprintf(
cmd,
sizeof(
cmd),
"ESGx!");
832 if (nbytes_read != 9)
838 char num_str[16] = {0};
840 snprintf(num_str,
sizeof(num_str),
"0X%.4s", response + 4);
842 int mrate = (int)strtol(num_str,
nullptr, 0);
858 int tmotor, refmotor;
905 int nbytes_written = 0;
907 snprintf(
cmd,
sizeof(
cmd),
"ESSr%d%04X!", axis, mrate);
926 snprintf(
cmd,
sizeof(
cmd),
"ESGr%d", axis);
934 if (nbytes_read == 10)
936 tcflush(
fd, TCIFLUSH);
978bool set_pmc8_track_enabled(
int fd,
bool enabled)
985 int nbytes_written = 0;
987 snprintf(
cmd, 32,
":ST%d#", enabled ? 1 : 0);
1042 if (rate < 0) direction = !direction;
1058 int nbytes_read = 0;
1059 int nbytes_written = 0;
1068 snprintf(
cmd,
sizeof(
cmd),
"ESTr%04X!", rateval);
1091 if (nbytes_read != 9)
1097 tcflush(
fd, TCIFLUSH);
1196 char cmd[32], expresp[32];
1200 int nbytes_read = 0;
1201 int nbytes_written = 0;
1203 snprintf(
cmd,
sizeof(
cmd),
"ESSf%d%02X!", axis,
int(rate * 100));
1212 snprintf(expresp,
sizeof(expresp),
"ESGf%d%02X!", axis,
int(rate * 100));
1238 int nbytes_read = 0;
1239 int nbytes_written = 0;
1241 snprintf(
cmd,
sizeof(
cmd),
"ESGf%d!", axis);
1258 if (nbytes_read != 8)
1264 char num_str[16] = {0};
1266 snprintf(num_str,
sizeof(num_str),
"0X%.2s", response + 5);
1267 int tint = strtol(num_str,
nullptr, 0);
1269 rate = ((double)tint) / 100;
1312 double cur_rate = 0;
1317 long long pulse_start_us;
1318 long long pulse_sofar_us;
1339 timetaken_us = ms * 1000;
1360 cur_rate = ratehint;
1366 cur_rate = ratehint;
1374 "pmc8_start_guide(): Cannot send guide correction while slewing! rate=%d dir=%d",
1379 double new_rate = cur_rate;
1393 "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.",
1394 cur_rate, new_rate);
1399 gettimeofday(&tp,
nullptr);
1400 pulse_start_us = tp.tv_sec * 1000000 + tp.tv_usec;
1419 bool effectiveSouth = (gdir ==
PMC8_S);
1425 if (new_rate < 0) new_dir = 1;
1440 if (cur_dir != new_dir)
1445 gettimeofday(&tp,
nullptr);
1446 pulse_start_us = tp.tv_sec * 1000000 + tp.tv_usec;
1469 gettimeofday(&tp,
nullptr);
1470 pulse_sofar_us = (tp.tv_sec * 1000000 + tp.tv_usec) - pulse_start_us;
1472 timetaken_us = pulse_sofar_us;
1482 long long pulse_end_us;
1500 tcflush(
fd, TCIFLUSH);
1511 gettimeofday(&tp,
nullptr);
1512 pulse_end_us = tp.tv_sec * 1000000 + tp.tv_usec;
1551 tcflush(
fd, TCIFLUSH);
1564 if (axispos > 8388608)
1565 r = 0 - (16777216 - axispos);
1582 hour_angle = lst -
ra;
1585 if (hour_angle > 12)
1586 hour_angle = hour_angle - 24;
1587 else if (hour_angle <= -12)
1588 hour_angle = hour_angle + 24;
1594 motor_angle = hour_angle - 6;
1596 motor_angle = hour_angle + 6;
1604 motor_angle = -(hour_angle + 6);
1606 motor_angle = -(hour_angle - 6);
1641 hour_angle = motor_angle + 6;
1643 hour_angle = motor_angle - 6;
1649 hour_angle = -(motor_angle + 6);
1651 hour_angle = -(motor_angle - 6);
1656 ra_value = lst - hour_angle;
1660 if (ra_value >= 24.0)
1661 ra_value = ra_value - 24.0;
1662 else if (ra_value < 0.0)
1663 ra_value = ra_value + 24.0;
1672 if (motor_angle >= 0)
1673 dec_value = 90 - motor_angle;
1675 dec_value = 90 + motor_angle;
1680 if (motor_angle >= 0)
1681 dec_value = -90 + motor_angle;
1683 dec_value = -90 - motor_angle;
1697 motor_angle = (
dec - 90.0);
1699 motor_angle = -(
dec - 90.0);
1707 motor_angle = -(
dec + 90.0);
1709 motor_angle = (
dec + 90.0);
1731 int nbytes_read = 0;
1732 int nbytes_written = 0;
1739 snprintf(
cmd,
sizeof(
cmd),
"ESPt%d%s!", naxis, hexpt);
1751 snprintf(expresp,
sizeof(expresp),
"ESGt%d%s!", naxis, hexpt);
1788 int nbytes_read = 0;
1789 int nbytes_written = 0;
1798 snprintf(
cmd,
sizeof(
cmd),
"ESSp%d%s!", axis, hexpt);
1807 snprintf(expresp,
sizeof(expresp),
"ESGp%d%s!", axis, hexpt);
1842 int nbytes_read = 0;
1843 int nbytes_written = 0;
1851 snprintf(
cmd,
sizeof(
cmd),
"ESGp%d!", axis);
1868 if (nbytes_read != 12)
1874 char num_str[16] = {0};
1876 snprintf(num_str,
sizeof(num_str),
"0X%.6s", response + 5);
1878 point = (int)strtol(num_str,
nullptr, 0);
1887 int axis_ra_pos, axis_dec_pos;
1978 int nbytes_read = 0;
1979 int nbytes_written = 0;
1981 snprintf(
cmd,
sizeof(
cmd),
"ESPt300000!");
1993 snprintf(expresp,
sizeof(expresp),
"ESGt3!");
2011 int racounts, deccounts;
2057 hour_angle = lst -
ra;
2060 if (hour_angle > 12)
2061 hour_angle = hour_angle - 24;
2062 else if (hour_angle <= -12)
2063 hour_angle = hour_angle + 24;
2068 if (hour_angle < 0.0)
2076 if (hour_angle < 0.0)
2106 int racounts, deccounts;
2152 int racounts, deccounts;
2197 int racounts, deccounts;
2255 if (strstr(errmsg,
"Connection timed out") || strstr(errmsg,
"Bad"))
2261 if (*nbytes_read > 0)
2263 buf[*nbytes_read] =
'\0';
2273 strcpy(buf, buf + 7);
2274 *nbytes_read = *nbytes_read - 7;
2277 if (strncmp(buf,
"AT", 2) == 0)
2279 strcpy(buf, buf + 2);
2280 *nbytes_read = *nbytes_read - 2;
2283 if (strncmp(buf,
"ESGp!", 5) == 0)
2292 if (strncmp(buf, expected, strlen(expected)) != 0)
2329 tcflush(
fd, TCIFLUSH);
2333 if ((err_code =
tty_write(
fd, buf, nbytes, nbytes_written)))
2337 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 sidereal 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)
INDI::Telescope::TelescopePierSide currentSideOfPier(int decCounts)
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)
bool get_pmc8_coords(int fd, double &ra, double &dec, INDI::Telescope::TelescopePierSide &sop)
#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 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)
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)