30#include <libnova/julian_day.h>
38#define CELESTRON_TIMEOUT 5
47 angle = angle - 360 * floor(angle / 360);
51 if ((angle > 90.) && (angle <= 270.))
53 else if ((angle > 270.) && (angle <= 360.))
62 angle = angle - 360 * floor(angle / 360);
66 return static_cast<uint16_t
>(angle * 0x10000 / 360.0);
72 angle = angle - 360 * floor(angle / 360);
76 return static_cast<uint32_t
>(angle * 0x100000000 / 360.0);
82 return 360.0 * (
static_cast<double>(value) / 0x10000);
88 return 360.0 * (
static_cast<double>(value) / 0x100000000);
91void hex_dump(
char *buf,
const char *data,
size_t size)
93 for (
size_t i = 0; i < size; i++)
94 sprintf(buf + 3 * i,
"%02X ", data[i]);
97 buf[3 * size - 1] =
'\0';
114 tcflush(
fd, TCIOFLUSH);
138 vsprintf(response,
fmt, args);
148 size_t resp_len,
bool ascii_cmd,
bool ascii_resp)
151 size_t nbytes = resp_len;
168 if ((err =
serial_write(
cmd,
static_cast<int>(cmd_len),
reinterpret_cast<int *
>(&nbytes))) !=
TTY_OK)
181 err =
serial_read(
static_cast<int>(resp_len),
reinterpret_cast<int *
>(&nbytes));
183 while (err ==
TTY_OK && resp[nbytes - 1] !=
'#')
204 if (nbytes != resp_len)
206 size_t max = nbytes > resp_len ? nbytes : resp_len;
208 LOGF_DEBUG(
"Received %d bytes, expected %d <%s>", nbytes, resp_len, hexbuf);
214 LOG_DEBUG(
"resp_len 0, no response expected");
235 size_t payload_len,
char *resp,
size_t response_len)
240 cmd[1] =
static_cast<char>(payload_len + 1);
241 cmd[2] =
static_cast<char>(dest);
242 cmd[3] =
static_cast<char>(cmd_id);
243 cmd[7] =
static_cast<char>(response_len);
246 memcpy(
cmd + 4, payload, payload_len);
253 LOG_DEBUG(
"Initializing Celestron using Kx CMD...");
255 for (
int i = 0; i < 2; i++)
268 char version[8],
model[16], RAVersion[8], DEVersion[8];
273 LOG_DEBUG(
"Getting controller version...");
279 LOG_DEBUG(
"Getting controller variant...");
293 LOG_DEBUG(
"Getting controller model...");
303 info->
Model =
"Unknown";
316 LOG_DEBUG(
"Getting RA firmware version...");
321 LOG_DEBUG(
"Getting DEC firmware version...");
330 LOGF_DEBUG(
"Firmware Info HC Ver %s model %s %s %s mount, HW Ver %s",
334 info->
isGem ?
"GEM" :
"Fork",
358 if (
static_cast<uint8_t
>(
response[0]) > 2)
359 snprintf(version, size,
"%d.%02d",
static_cast<uint8_t
>(
response[0]),
static_cast<uint8_t
>(
response[1]));
361 snprintf(version, size,
"%d.%d",
static_cast<uint8_t
>(
response[0]),
static_cast<uint8_t
>(
response[1]));
363 LOGF_INFO(
"Controller version: %s", version);
375 *variant =
static_cast<uint8_t
>(
response[0]);
385 return static_cast<uint8_t
>(
response[0]);
391 std::map<int, std::string> models =
426 if (models.find(m) != models.end())
428 snprintf(
model, size,
"%s", models[m].c_str());
433 snprintf(
model, size,
"%s",
"Unknown");
475 *hasHomeIndex = (m == 23 || m == 24);
477 LOGF_DEBUG(
"get_model %s, %s mount, %s, %s",
model, *isGem ?
"GEM" :
"Fork", *canPec ?
"has PEC" :
"no PEC",
478 *hasHomeIndex ?
"has home indexes" :
"no home indexes");
492 snprintf(version, size,
"%01d.0",
static_cast<uint8_t
>(
response[0]));
495 snprintf(version, size,
"%d.%02d",
static_cast<uint8_t
>(
response[0]),
static_cast<uint8_t
>(
response[1]));
539 payload[1] = duration_csec;
571 return static_cast<bool>(
response[0]);
595 *rate =
static_cast<uint8_t
>(
response[0]);
596 LOGF_DEBUG(
"get_guide_rate raw response (0-255) %i", *rate);
630 payload[0] = rate + 1;
639 char payload[] = { 0 };
653 char RAStr[16], DecStr[16];
657 LOGF_DEBUG(
"Goto RA-DEC(%s,%s)", RAStr, DecStr);
673 char AzStr[16], AltStr[16];
677 LOGF_DEBUG(
"Goto AZM-ALT (%s,%s)", AzStr, AltStr);
693 char RAStr[16], DecStr[16];
722 uint32_t d1_int = 0, d2_int = 0;
724 sscanf(response,
"%x,%x#", &d1_int, &d2_int);
759 char RAStr[16], DecStr[16];
786 char AzStr[16], AltStr[16];
788 fs_sexa(AltStr, *alt, 2, 3600);
795 LOGF_DEBUG(
"Setting location (%.3f,%.3f)", longitude, latitude);
801 int lat_d, lat_m, lat_s;
802 int long_d, long_m, long_s;
808 cmd[1] =
static_cast<char>(abs(lat_d));
809 cmd[2] =
static_cast<char>(lat_m);
810 cmd[3] =
static_cast<char>(lat_s);
811 cmd[4] = lat_d > 0 ? 0 : 1;
812 cmd[5] =
static_cast<char>(abs(
814 cmd[6] =
static_cast<char>(long_m);
815 cmd[7] =
static_cast<char>(long_s);
816 cmd[8] = longitude > 0 ? 0 : 1;
834 *latitude = -*latitude;
840 *longitude = -*longitude;
852 struct ln_zonedate local_date;
855 ln_date_to_zonedate(utc, &local_date,
static_cast<int>(utc_offset * 3600));
859 cmd[1] =
static_cast<char>(local_date.hours);
860 cmd[2] =
static_cast<char>(local_date.minutes);
861 cmd[3] =
static_cast<char>(local_date.seconds);
862 cmd[4] =
static_cast<char>(local_date.months);
863 cmd[5] =
static_cast<char>(local_date.days);
864 cmd[6] =
static_cast<char>(local_date.years - 2000);
866 int utc_int =
static_cast<int>(utc_offset);
875 cmd[7] =
static_cast<char>(utc_int & 0xFF);
878 cmd[8] = dst ? 1 : 0;
885 int *dd,
int *hh,
int *minute,
int *ss,
bool* dst,
bool precise)
891 time_t now = time(
nullptr);
892 tm *ltm = localtime(&now);
895 ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
896 ltm->tm_mon, ltm->tm_mday, ltm->tm_year - 100,
897 precise ? ltm->tm_gmtoff / 900 : ltm->tm_gmtoff / 3600, ltm->tm_isdst);
906 ln_zonedate localTime;
915 localTime.years = 2000 +
response[5];
926 *utc_hours = gmtoff / 4;
927 localTime.gmtoff = gmtoff * 900;
932 localTime.gmtoff = gmtoff * 3600;
938 localTime.gmtoff += 3600;
946 ln_zonedate_to_date(&localTime, &utcTime);
949 *mm = utcTime.months;
952 *minute = utcTime.minutes;
953 *ss =
static_cast<int>(utcTime.seconds);
985 sprintf(
cmd,
"T%c", mode);
1022 bool atDecIndex =
response[0] !=
'\00';
1025 bool atRaIndex =
response[0] !=
'\00';
1026 *atIndex = atDecIndex && atRaIndex;
1069 char payload[] = {
static_cast<char>(rate >> 8 & 0xff),
static_cast<char>(rate & 0xff)};
1077 char focVersion[16];
1085 snprintf(focVersion, 15,
"%d.%02d",
static_cast<uint8_t
>(
response[0]),
static_cast<uint8_t
>(
response[1]));
1086 vernum = (
static_cast<uint8_t
>(
response[0]) << 24) + (
static_cast<uint8_t
>(
response[1]) << 16);
1090 snprintf(focVersion, 15,
"%d.%02d.%d",
1092 static_cast<int>((
static_cast<uint8_t
>(
response[2]) << 8) +
static_cast<uint8_t
>(
response[3])));
1093 vernum = (
static_cast<uint8_t
>(
response[0]) << 24) + (
static_cast<uint8_t
>(
response[1]) << 16) + (
static_cast<uint8_t
>
1101 LOGF_DEBUG(
"Focuser Version %s, exists %s", focVersion, vernum != 0 ?
"true" :
"false");
1112 else if (offset < -250)
1123 int pos = (
static_cast<uint8_t
>(
response[0]) << 16) + (
static_cast<uint8_t
>(
response[1]) << 8) +
static_cast<uint8_t
>
1136 char payload[] = {
static_cast<char>(steps >> 16 & 0xff),
static_cast<char>(steps >> 8 & 0xff),
static_cast<char>(steps & 0xff)};
1159 *low = (
static_cast<uint8_t
>(
response[0]) << 24) + (
static_cast<uint8_t
>(
response[1]) << 16) + (
static_cast<uint8_t
>
1161 *high = (
static_cast<uint8_t
>(
response[4]) << 24) + (
static_cast<uint8_t
>(
response[5]) << 16) + (
static_cast<uint8_t
>
1165 if (*high - *low < 2000 || *high < 0 || *high > 60000 || *low < 0 || *low > 50000)
1167 LOGF_INFO(
"Focus range %i to %i invalid, range not updated", *high, *low);
1171 LOGF_DEBUG(
"Focus Limits: Maximum (%i) Minimum (%i)", *high, *low);
1183 char payload[] = {0};
1196 LOG_DEBUG(
"PecSeekIndex - already found");
1205 LOG_WARN(
"Start PEC seek index failed");
1232 bool indexed = (
response[0] ==
'\xFF');
1240 LOGF_DEBUG(
"isPecAtIndex? %s", indexed ?
"yes" :
"no");
1249 LOG_DEBUG(
"getPecNumBins - PEC not available");
1253 char payload[] = { 0x3F };
1286 data[0] = start ? 0x01 : 0x00;
1293 LOGF_WARN(
"PEC Playback %s failed", start ?
"start" :
"stop");
1318 LOGF_WARN(
"PEC Record %s failed", start ?
"start" :
"stop");
1343 LOGF_DEBUG(
"isPecRecordDone %s", done ?
"yes" :
"no");
1353 int val =
static_cast<int>(std::round(std::cos(index * 2.0 * 3.14192 / 87.0) * 100.0));
1354 if (val < 0) val = 256 + val;
1357 char data[] = {
static_cast<char>(0x40 + index) };
1369 payload[0] =
static_cast<char>(0x40 + index);
1370 payload[1] =
static_cast<char>((data < 127) ? data : 256 - data);
1403 return "Not Available";
1407 return "PEC Playback";
1409 return "seeking index";
1411 return "Index Found";
1413 return "PEC Recording";
1425 for (
size_t i = 0; i <= numBins; ++i)
1427 double p = i * 2.0 * 3.14192 / numBins;
1428 data[i] = std::sin(p) * 5;
1430 wormArcSeconds = 7200;
1437 int mountType = driver->
model();
1438 rateScale = (mountType <= 2) ? 512 : 1024;
1439 wormArcSeconds = mountType == 8 ? 3600 : 7200;
1443 if (numBins < 88 || numBins > 254)
1446 double posError = 0;
1448 for (
size_t i = 0; i < numBins; i++)
1461 double binRate = rawPec * SIDEREAL_ARCSEC_PER_SEC / rateScale;
1462 double binTime = (wormArcSeconds / numBins) / (SIDEREAL_ARCSEC_PER_SEC + binRate);
1463 posError += binRate * binTime;
1464 data[i + 1] = posError;
1466 LOGF_DEBUG(
"i %d, rawPec %d, binRate %f, binTime %f, data[%d] %f", i, rawPec, binRate, binTime, i + 1, data[i + 1]);
1481 std::ifstream pecFile(fileName);
1483 if (pecFile.is_open())
1486 for (
size_t i = 0; i <= numBins; i++)
1490 pecFile >> wormArcSeconds;
1491 LOGF_DEBUG(
"PEC Load File %s, numBins %d, wormarcsecs %d", fileName, numBins, wormArcSeconds);
1497 LOGF_WARN(
"Load PEC file %s, error %s", fileName, strerror(
errno));
1506 std::ofstream pecFile(filename);
1507 if (!pecFile.is_open())
1510 pecFile << numBins <<
"\n";
1511 for (
size_t i = 0; i <= numBins; i++)
1513 pecFile << data[i] <<
"\n";
1516 pecFile << wormArcSeconds <<
"\n";
1529 for (
size_t i = 0; i < numBins; i++)
1536 deltaDist = data[i + 1] - data[i];
1538 double rawPecData = deltaDist * SIDEREAL_ARCSEC_PER_SEC / (wormArcSeconds / numBins - deltaDist);
1540 int rawdata =
static_cast<int>(std::round(rawPecData * rateScale / SIDEREAL_ARCSEC_PER_SEC));
1541 LOGF_DEBUG(
"i %d, deltaDist %f, rawPecdata %f, rawData %d", i, deltaDist, rawPecData, rawdata);
1556 double delta = (data[numBins] - data[0]) / numBins;
1557 double offset = data[0];
1558 for (
size_t i = 0; i <= numBins; i++)
1560 data[i] = data[i] - offset - delta * i;
1564void PecData::Kalman(
PecData newData,
int num)
1566 if (numBins != newData.numBins)
1571 auto fraction = 1.0 / num;
1572 auto kf = 1 - fraction;
1574 for (
size_t i = 0; i <= numBins; i++)
1576 data[i] = data[i] * kf + newData.data[i] * fraction;
std::string fmt(const char *fmt,...)
void parseCoordsResponse(char *response, double *d1, double *d2, bool precise)
void hex_dump(char *buf, const char *data, size_t size)
__attribute__((__format__(__printf__, 2, 0))) void CelestronDriver
#define CELESTRON_TIMEOUT
#define MC_PEC_RECORD_DONE
#define MC_SET_NEG_GUIDERATE
#define MC_PEC_RECORD_STOP
#define MC_PEC_RECORD_START
#define FOC_GET_HS_POSITIONS
#define MC_PEC_WRITE_DATA
#define CELESTRON_DEV_FOC
@ PEC_SEEKING
The PEC index is being searched for, goes to PEC_INDEXED when found.
@ PEC_AVAILABLE
PEC is available but inactive, can seek index Seek index is only available command.
@ PEC_PLAYBACK
PEC is being played back, stays in this state until stopped equivalent to TelescopePECState PEC_ON.
@ PEC_RECORDING
PEC is being recorded, goes to PEC_INDEXED when completed.
@ PEC_NOT_AVAILABLE
PEC is not available, hardware has been checked, no other state is possible.
@ PEC_INDEXED
the PEC index has been found, can go to Playback or Recording this is equivalent to TelescopePECState...
#define CELESTRON_DEV_DEC
#define MC_SET_AUTOGUIDE_RATE
#define MC_GET_AUTOGUIDE_RATE
#define MC_SET_POS_GUIDERATE
#define MTR_IS_AUX_GUIDE_ACTIVE
bool slew_radec(double ra, double dec, bool precise)
bool get_azalt(double *az, double *alt, bool precise)
bool set_guide_rate(CELESTRON_AXIS axis, uint8_t rate)
bool indexreached(bool *atIndex)
bool check_aligned(bool *isAligned)
bool set_datetime(struct ln_date *utc, double utc_offset, bool dst=false, bool precise=false)
bool set_location(double longitude, double latitude)
bool stop_motion(CELESTRON_DIRECTION dir)
int getPecValue(size_t index)
bool get_firmware(FirmwareInfo *info)
bool sync(double ra, double dec, bool precise)
bool foc_limits(int *low, int *high)
bool PecPlayback(bool start)
bool get_dev_firmware(int dev, char *version, size_t size)
size_t send_pulse(CELESTRON_DIRECTION direction, unsigned char rate, unsigned char duration_msec)
size_t send_passthrough(int dest, int cmd_id, const char *payload, size_t payload_len, char *resp, size_t response_len)
bool get_radec(double *ra, double *dec, bool precise)
bool get_track_mode(CELESTRON_TRACK_MODE *mode)
void move_sim_foc(int offset)
void set_device(const char *name)
bool set_track_rate(CELESTRON_TRACK_RATE rate, CELESTRON_TRACK_MODE mode)
bool set_track_mode(CELESTRON_TRACK_MODE mode)
bool get_model(char *model, size_t size, bool *isGem, bool *canPec, bool *hasHomeIndex)
bool get_version(char *version, size_t size)
size_t send_command(const char *cmd, size_t cmd_len, char *resp, size_t resp_len, bool ascii_cmd, bool ascii_resp)
char response[MAX_RESP_SIZE]
virtual int serial_read(int nbytes, int *nbytes_read)
const char * PecStateStr()
void set_sim_response(const char *fmt,...)
bool PecRecord(bool start)
bool isPecAtIndex(bool force=false)
bool get_variant(char *variant)
bool get_location(double *longitude, double *latitude)
const char * getDeviceName()
bool get_pulse_status(CELESTRON_DIRECTION direction)
void set_sim_slewing(bool isSlewing)
virtual int serial_write(const char *cmd, int nbytes, int *nbytes_written)
PEC_STATE updatePecState()
virtual int serial_read_section(char stop_char, int *nbytes_read)
bool get_guide_rate(CELESTRON_AXIS axis, uint8_t *rate)
bool slew_azalt(double az, double alt, bool precise)
bool setPecValue(size_t index, int data)
bool foc_move(uint32_t steps)
bool get_pier_side(char *sop)
bool is_slewing(bool *slewing)
bool get_utc_date_time(double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss, bool *dst, bool precise)
bool start_motion(CELESTRON_DIRECTION dir, CELESTRON_SLEW_RATE rate)
const char * getDeviceName()
bool Load(CelestronDriver *driver)
bool Save(const char *filename)
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
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[].
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Implementations for common driver routines.
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOGF_ERROR(fmt,...)
#define LOGF_EXTRA1(fmt,...)
double pnex2dd(uint32_t value)
uint32_t dd2pnex(double angle)
uint16_t dd2nex(double angle)
double trimDecAngle(double angle)
double nex2dd(uint32_t value)