25#include <libnova/transform.h>
26#include <libnova/precession.h>
29#include <libnova/utility.h>
38constexpr uint16_t SynscanDriver::SIM_SLEW_RATE[];
44 m_MountInfo.push_back(
"--");
45 m_MountInfo.push_back(
"--");
46 m_MountInfo.push_back(
"--");
47 m_MountInfo.push_back(
"--");
48 m_MountInfo.push_back(
"--");
83 IUFillText(&StatusT[MI_FW_VERSION],
"MI_FW_VERSION",
"Firmware",
"-");
84 IUFillText(&StatusT[MI_MOUNT_MODEL],
"MI_MOUNT_MODEL",
"Model",
"-");
85 IUFillText(&StatusT[MI_GOTO_STATUS],
"MI_GOTO_STATUS",
"Goto",
"-");
86 IUFillText(&StatusT[MI_POINT_STATUS],
"MI_POINT_STATUS",
"Pointing",
"-");
87 IUFillText(&StatusT[MI_TRACK_MODE],
"MI_TRACK_MODE",
"Tracking Mode",
"-");
94 IUFillNumber(&CustomSlewRateN[
AXIS_RA],
"AXIS1",
"RA/AZ (arcsecs/s)",
"%.2f", 0.05, 800, 10, 0);
95 IUFillNumber(&CustomSlewRateN[
AXIS_DE],
"AXIS2",
"DE/AL (arcsecs/s)",
"%.2f", 0.05, 800, 10, 0);
185void SynscanDriver::setupParams()
195int SynscanDriver::hexStrToInteger(
const std::string &res)
201 result = std::stoi(res,
nullptr, 16);
203 catch (std::invalid_argument &)
205 LOGF_ERROR(
"Failed to parse %s to integer.", res.c_str());
213 char res[SYN_RES] = {0};
218 if (!sendCommand(
"J", res))
223 LOG_ERROR(
"Mount is not aligned. Please align the mount first and connect again.");
246 if (strcmp(name,
"GUIDE_RATE") == 0)
255 if (strcmp(name, CustomSlewRateNP.
name) == 0)
259 LOG_ERROR(
"Cannot change rate while slewing.");
272 if (!strcmp(name, HorizontalCoordsNP.
name))
276 LOG_WARN(
"Unpark mount before issuing GOTO commands.");
283 double newAlt = 0, newAz = 0;
284 for (
int i = 0; i < n; i++)
287 if (horp == &HorizontalCoordsN[
AXIS_AZ])
290 nset += newAz >= 0. && newAz <= 360.0;
292 else if (horp == &HorizontalCoordsN[
AXIS_ALT])
295 nset += newAlt >= -90. && newAlt <= 90.0;
299 if (nset == 2 &&
GotoAzAlt(newAz, newAlt))
303 IDSetNumber(&HorizontalCoordsNP,
"Altitude or Azimuth missing or invalid.");
317 if (svp.isNameMatch(GotoModeSP.
name))
319 svp.update(states, names, n);
320 auto sp = svp.findOnSwitch();
322 assert(sp !=
nullptr);
324 if (sp->isNameMatch(GotoModeS[0].name))
336bool SynscanDriver::echo()
338 char res[SYN_RES] = {0};
339 return sendCommand(
"Kx", res);
342bool SynscanDriver::readFirmware()
345 char res[SYN_RES] = {0};
346 if (sendCommand(
"V", res))
348 m_FirmwareVersion =
static_cast<double>(hexStrToInteger(std::string(&res[0], 2)));
349 m_FirmwareVersion +=
static_cast<double>(hexStrToInteger(std::string(&res[2], 2))) / 100;
350 m_FirmwareVersion +=
static_cast<double>(hexStrToInteger(std::string(&res[4], 2))) / 10000;
352 LOGF_INFO(
"Firmware version: %lf", m_FirmwareVersion);
353 m_MountInfo[MI_FW_VERSION] = std::to_string(m_FirmwareVersion);
354 IUSaveText(&StatusT[MI_FW_VERSION], m_MountInfo[MI_FW_VERSION].c_str());
356 if (m_FirmwareVersion < 3.38 || (m_FirmwareVersion >= 4.0 && m_FirmwareVersion < 4.38))
358 LOGF_WARN(
"Firmware version is too old. Update Synscan firmware to %s",
359 m_FirmwareVersion < 3.38 ?
"v3.38+" :
"v4.38+");
366 LOG_WARN(
"Firmware version is too old. Update Synscan firmware to v4.38+");
371bool SynscanDriver::readTracking()
374 char res[SYN_RES] = {0};
375 if (sendCommand(
"t", res))
378 m_TrackingFlag = res[0];
391 m_MountInfo[MI_TRACK_MODE] =
"Tracking off";
394 m_MountInfo[MI_TRACK_MODE] =
"Alt/Az tracking";
397 m_MountInfo[MI_TRACK_MODE] =
"EQ tracking";
400 m_MountInfo[MI_TRACK_MODE] =
"PEC mode";
410bool SynscanDriver::readModel()
413 std::map<int, std::string> models =
415 {0,
"EQ6 GOTO Series"},
416 {1,
"HEQ5 GOTO Series"},
417 {2,
"EQ5 GOTO Series"},
418 {3,
"EQ3 GOTO Series"},
419 {4,
"EQ8 GOTO Series"},
420 {5,
"AZ-EQ6 GOTO Series"},
421 {6,
"AZ-EQ5 GOTO Series"},
422 {160,
"AllView GOTO Series"},
423 {161,
"Virtuoso Alt/Az mount"},
424 {165,
"AZ-GTi GOTO Series"}
428 char res[SYN_RES] = {0};
430 if (!sendCommand(
"m", res))
433 m_MountModel = res[0];
436 if (m_MountModel >= 128 && m_MountModel <= 143)
437 IUSaveText(&StatusT[MI_MOUNT_MODEL],
"AZ GOTO Series");
439 else if (m_MountModel >= 144 && m_MountModel <= 159)
440 IUSaveText(&StatusT[MI_MOUNT_MODEL],
"Dob GOTO Series");
441 else if (models.count(m_MountModel) > 0)
442 IUSaveText(&StatusT[MI_MOUNT_MODEL], models[m_MountModel].c_str());
444 IUSaveText(&StatusT[MI_MOUNT_MODEL],
"Unknown model");
446 m_isAltAz = m_MountModel > 4;
448 LOGF_INFO(
"Driver is running in %s mode.", m_isAltAz ?
"Alt-Az" :
"Equatorial");
449 LOGF_INFO(
"Detected mount: %s. Mount must be aligned from the handcontroller before using the driver.",
450 StatusT[MI_MOUNT_MODEL].text);
463 char res[SYN_RES] = {0};
466 if (sendCommand(
"L", res))
467 m_MountInfo[MI_GOTO_STATUS] = res[0];
470 if (m_isAltAz ==
false && sendCommand(
"p", res))
472 m_MountInfo[MI_POINT_STATUS] = res[0];
481 if (isSlewComplete())
490 if (isSlewComplete())
508 memset(res, 0, SYN_RES);
509 if (!sendCommand(
"e", res))
512 uint32_t n1 = 0, n2 = 0;
513 sscanf(res,
"%x,%x#", &n1, &n2);
514 double ra =
static_cast<double>(n1) / 0x100000000 * 360.0;
515 double de =
static_cast<double>(n2) / 0x100000000 * 360.0;
519 J2000Pos.declination =
rangeDec(de);
524 CurrentRA = epochPos.rightascension;
525 CurrentDE = epochPos.declination;
528 fs_sexa(Axis1Coords, J2000Pos.rightascension, 2, 3600);
529 fs_sexa(Axis2Coords, J2000Pos.declination, 2, 3600);
530 LOGF_DEBUG(
"J2000 RA <%s> DE <%s>", Axis1Coords, Axis2Coords);
533 fs_sexa(Axis1Coords, CurrentRA, 2, 3600);
534 fs_sexa(Axis2Coords, CurrentDE, 2, 3600);
535 LOGF_DEBUG(
"JNOW RA <%s> DE <%s>", Axis1Coords, Axis2Coords);
541 memset(res, 0, SYN_RES);
542 if (!sendCommand(
"z", res))
545 sscanf(res,
"%x,%x#", &n1, &n2);
546 double az =
static_cast<double>(n1) / 0x100000000 * 360.0;
547 double al =
static_cast<double>(n2) / 0x100000000 * 360.0;
550 HorizontalCoordsN[
AXIS_AZ].value = az;
551 HorizontalCoordsN[
AXIS_ALT].value = al;
555 fs_sexa(Axis1Coords, az, 2, 3600);
556 fs_sexa(Axis2Coords, al, 2, 3600);
557 LOGF_DEBUG(
"AZ <%s> ALT <%s>", Axis1Coords, Axis2Coords);
566 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
573 return sendCommand(
cmd, res, 2);
578 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
585 return sendCommand(
cmd, res);
588bool SynscanDriver::SetAltAzMode(
bool enable)
624 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
636 epochPos.declination =
dec;
639 if (goto_AltAz && m_isAltAz)
653 double dec_pos = J2000Pos.declination;
654 if (J2000Pos.declination < 0)
655 dec_pos = dec_pos + 360;
657 uint32_t n1 = J2000Pos.rightascension * 15.0 / 360 * 0x100000000;
658 uint32_t n2 = dec_pos / 360 * 0x100000000;
660 LOGF_DEBUG(
"Goto - JNow RA: %g JNow DE: %g J2000 RA: %g J2000 DE: %g",
ra,
dec, J2000Pos.rightascension,
661 J2000Pos.declination);
663 snprintf(
cmd, SYN_RES,
"r%08X,%08X", n1, n2);
664 if (sendCommand(
cmd, res, 18))
677 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
682 if (m_isAltAz ==
false)
694 uint32_t n1 = az / 360.0 * 0x100000000;
695 uint32_t n2 = alt / 360.0 * 0x100000000;
697 LOGF_DEBUG(
"Goto - Az: %.2f Alt: %.2f", az, alt);
699 snprintf(
cmd, SYN_RES,
"b%08X,%08X", n1, n2);
700 if (sendCommand(
cmd, res, 18))
716 char AzStr[16], AltStr[16];
717 fs_sexa(AzStr, parkAZ, 2, 3600);
718 fs_sexa(AltStr, parkAlt, 2, 3600);
719 LOGF_DEBUG(
"Parking to Az (%s) Alt (%s)...", AzStr, AltStr);
724 LOG_INFO(
"Parking is in progress...");
741 char res[SYN_RES] = {0};
744 memset(res, 0, SYN_RES);
745 if (!sendCommand(
"z", res))
748 uint32_t n1 = 0, n2 = 0;
749 sscanf(res,
"%ux,%ux#", &n1, &n2);
750 double az =
static_cast<double>(n1) / 0x100000000 * 360.0;
751 double al =
static_cast<double>(n2) / 0x100000000 * 360.0;
754 char AzStr[16], AltStr[16];
758 LOGF_DEBUG(
"Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr, AltStr);
769 LOG_DEBUG(
"Setting Park Data to Default.");
807 double customRate = CustomSlewRateN[
AXIS_DE].value;
810 if (m_CustomGuideDE > 0)
813 customRate = m_CustomGuideDE;
819 rc = (rate < 10) ? slewFixedRate(move, rate) : slewVariableRate(move, customRate);
822 LOG_ERROR(
"Error setting N/S motion direction.");
826 else if (!m_CustomGuideDE)
827 LOGF_INFO(
"Moving toward %s.", (move ==
SYN_N) ?
"North" :
"South");
831 if (slewFixedRate(move, 0) ==
false)
836 else if (!m_CustomGuideDE)
837 LOGF_INFO(
"Movement toward %s halted.", (move ==
SYN_N) ?
"North" :
"South");
852 double customRate = CustomSlewRateN[
AXIS_RA].value;
855 if (m_CustomGuideRA > 0)
858 customRate = m_CustomGuideRA;
864 rc = (rate < 10) ? slewFixedRate(move, rate) : slewVariableRate(move, customRate);
867 LOG_ERROR(
"Error setting W/E motion direction.");
871 else if (!m_CustomGuideRA)
872 LOGF_INFO(
"Moving toward %s.", (move ==
SYN_W) ?
"West" :
"East");
876 if (slewFixedRate(move, 0) ==
false)
881 else if (!m_CustomGuideRA)
882 LOGF_INFO(
"Movement toward %s halted.", (move ==
SYN_W) ?
"West" :
"East");
891 m_TargetSlewRate = s + 1;
896bool SynscanDriver::passThruCommand(
int cmd,
int target,
int msgsize,
int data,
int numReturn)
899 int bytesRead, bytesWritten;
931 retval = retval << 8;
936 retval = retval << 8;
946bool SynscanDriver::sendTime()
953 time_t now = time (
nullptr);
954 strftime(timeString,
MAXINDINAME,
"%T", gmtime(&now));
962 char res[SYN_RES] = {0};
963 if (sendCommand(
"h", res))
965 ln_zonedate localTime;
967 int offset, daylightflag;
969 localTime.hours = res[0];
970 localTime.minutes = res[1];
971 localTime.seconds = res[2];
972 localTime.months = res[3];
973 localTime.days = res[4];
974 localTime.years = res[5];
975 offset =
static_cast<int>(res[6]);
979 localTime.gmtoff = offset;
981 daylightflag = res[7];
982 localTime.years += 2000;
983 localTime.gmtoff *= 3600;
985 ln_zonedate_to_date(&localTime, &utcTime);
991 sec =
static_cast<int>(utcTime.seconds);
992 sprintf(utc,
"%04d-%02d-%dT%d:%02d:%02d", utcTime.years, utcTime.months, utcTime.days, utcTime.hours,
993 utcTime.minutes, sec);
994 if (daylightflag == 1)
996 snprintf(ofs, 16,
"%d", offset);
1003 LOGF_INFO(
"Mount UTC Time %s Offset %d", utc, offset);
1010bool SynscanDriver::sendLocation()
1012 char res[SYN_RES] = {0};
1024 if (!sendCommand(
"w", res))
1029 int a, b, c, d, e, f, g, h;
1065 char LongitudeStr[32] = {0}, LatitudeStr[32] = {0};
1066 fs_sexa(LongitudeStr, lon, 2, 3600);
1067 fs_sexa(LatitudeStr, lat, 2, 3600);
1068 LOGF_INFO(
"Mount Longitude %s Latitude %s", LongitudeStr, LatitudeStr);
1075 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
1079 struct ln_zonedate ltm;
1081 ln_date_to_zonedate(utc, <m, utc_offset * 3600.0);
1089 cmd[2] = ltm.minutes;
1090 cmd[3] =
static_cast<char>(ltm.seconds);
1091 cmd[4] = ltm.months;
1095 cmd[7] = utc_offset > 0 ?
static_cast<uint8_t
>(utc_offset) :
static_cast<uint8_t
>(256 + utc_offset);
1099 LOGF_INFO(
"Setting mount date/time to %04d-%02d-%02d %d:%02d:%02d UTC Offset: %.2f",
1100 ltm.years, ltm.months, ltm.days, ltm.hours, ltm.minutes,
static_cast<int>(rint(ltm.seconds)), utc_offset);
1105 return sendCommand(
cmd, res, 9);
1111 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
1112 bool IsWest =
false;
1114 ln_lnlat_posn p1 { 0, 0 };
1125 CurrentDE = latitude > 0 ? 90 : -90;
1131 if (longitude > 180)
1133 p1.lng = 360.0 - longitude;
1141 ln_lnlat_to_hlnlat(&p1, &p2);
1142 LOGF_INFO(
"Update location to latitude %d:%d:%1.2f longitude %d:%d:%1.2f",
1143 p2.lat.degrees, p2.lat.minutes, p2.lat.seconds, p2.lng.degrees, p2.lng.minutes, p2.lng.seconds);
1146 cmd[1] = p2.lat.degrees;
1147 cmd[2] = p2.lat.minutes;
1148 cmd[3] = rint(p2.lat.seconds);
1149 cmd[4] = (p2.lat.neg == 0) ? 0 : 1;
1150 cmd[5] = p2.lng.degrees;
1151 cmd[6] = p2.lng.minutes;
1152 cmd[7] = rint(p2.lng.seconds);
1153 cmd[8] = IsWest ? 1 : 0;
1155 return sendCommand(
cmd, res, 9);
1160 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
1171 epochPos.declination =
dec;
1177 uint32_t n1 = J2000Pos.rightascension * 15.0 / 360 * 0x100000000;
1178 uint32_t n2 = J2000Pos.declination / 360 * 0x100000000;
1180 LOGF_DEBUG(
"Sync - JNow RA: %g JNow DE: %g J2000 RA: %g J2000 DE: %g",
ra,
dec, J2000Pos.rightascension,
1181 J2000Pos.declination);
1183 snprintf(
cmd, SYN_RES,
"s%08X,%08X", n1, n2);
1184 return sendCommand(
cmd, res, 18);
1187void SynscanDriver::sendStatus()
1189 bool BasicMountInfoHasChanged =
false;
1191 if (std::string(StatusT[MI_GOTO_STATUS].text) != m_MountInfo[MI_GOTO_STATUS])
1193 IUSaveText(&StatusT[MI_GOTO_STATUS], m_MountInfo[MI_GOTO_STATUS].c_str());
1194 BasicMountInfoHasChanged =
true;
1196 if (std::string(StatusT[MI_POINT_STATUS].text) != m_MountInfo[MI_POINT_STATUS])
1198 IUSaveText(&StatusT[MI_POINT_STATUS], m_MountInfo[MI_POINT_STATUS].c_str());
1199 BasicMountInfoHasChanged =
true;
1201 if (std::string(StatusT[MI_TRACK_MODE].text) != m_MountInfo[MI_TRACK_MODE])
1203 IUSaveText(&StatusT[MI_TRACK_MODE], m_MountInfo[MI_TRACK_MODE].c_str());
1204 BasicMountInfoHasChanged =
true;
1207 if (BasicMountInfoHasChanged)
1214bool SynscanDriver::sendCommand(
const char *
cmd,
char * res,
int cmd_len,
int res_len)
1216 int nbytes_written = 0, nbytes_read = 0, rc = -1;
1218 tcflush(
PortFD, TCIOFLUSH);
1222 char hex_cmd[SYN_RES * 3] = {0};
1223 hexDump(hex_cmd,
cmd, cmd_len);
1237 LOGF_ERROR(
"Serial write error: %s.", errstr);
1253 LOGF_ERROR(
"Serial read error: %s.", errstr);
1259 char hex_res[SYN_RES * 3] = {0};
1260 hexDump(hex_res, res, res_len);
1268 tcflush(
PortFD, TCIOFLUSH);
1273void SynscanDriver::hexDump(
char * buf,
const char * data,
int size)
1275 for (
int i = 0; i < size; i++)
1276 sprintf(buf + 3 * i,
"%02X ",
static_cast<uint8_t
>(data[i]));
1279 buf[3 * size - 1] =
'\0';
1282void SynscanDriver::mountSim()
1284 static struct timeval ltv;
1290 gettimeofday(&tv,
nullptr);
1292 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1295 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1298 da = currentSlewRate * dt;
1305 CurrentRA =
range24(CurrentRA);
1316 dx = TargetRA - CurrentRA;
1324 CurrentRA = TargetRA;
1328 CurrentRA += da / 15.;
1330 CurrentRA -= da / 15.;
1334 else if (CurrentRA > 24)
1337 dx = TargetDE - CurrentDE;
1340 CurrentDE = TargetDE;
1365bool SynscanDriver::slewFixedRate(SynscanDirection direction, uint8_t rate)
1367 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
1372 cmd[2] = (direction ==
SYN_N || direction ==
SYN_S) ? 17 : 16;
1375 cmd[3] = (direction ==
SYN_N || direction ==
SYN_W) ? 36 : 37;
1377 cmd[3] = (direction ==
SYN_N || direction ==
SYN_W) ? 37 : 36;
1381 return sendCommand(
cmd, res, 8);
1384bool SynscanDriver::slewVariableRate(SynscanDirection direction,
double rate)
1386 char cmd[SYN_RES] = {0}, res[SYN_RES] = {0};
1390 uint16_t synRate = rint(rate * 4);
1395 cmd[2] = (direction ==
SYN_N || direction ==
SYN_S) ? 17 : 16;
1397 cmd[3] = (direction ==
SYN_N || direction ==
SYN_W) ? 6 : 7;
1399 cmd[4] = synRate >> 8;
1401 cmd[5] = synRate & 0xFF;
1403 return sendCommand(
cmd, res, 8);
1472 static_cast<SynscanDriver *
>(context)->guideTimeoutCallbackNS();
1477 static_cast<SynscanDriver *
>(context)->guideTimeoutCallbackWE();
1480void SynscanDriver::guideTimeoutCallbackNS()
1485 m_CustomGuideDE = m_GuideNSTID = 0;
1488void SynscanDriver::guideTimeoutCallbackWE()
1493 m_CustomGuideRA = m_GuideWETID = 0;
1496bool SynscanDriver::isSlewComplete()
1498 char res[SYN_RES] = {0};
1500 if (!sendCommand(
"L", res))
1503 return res[0] ==
'0';
INDI::PropertySwitch getSwitch(const char *name) const
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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 addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
uint32_t getDriverInterface() const
virtual void GuideComplete(INDI_EQ_AXIS axis)
Call GuideComplete once the guiding pulse is complete.
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
void initProperties(const char *groupName)
Initialize guider properties. It is recommended to call this function within initProperties() of your...
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void setLabel(const char *label)
int findOnSwitchIndex() const
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
double GetAxis2Park() const
bool isParked()
isParked is mount currently parked?
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
IGeographicCoordinates m_Location
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
virtual bool Park() override
Park the telescope to its home position.
static void guideTimeoutHelperWE(void *context)
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
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 SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
static void guideTimeoutHelperNS(void *context)
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual const char * getDefaultName() override
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool Handshake() override
perform handshake with device to check communication
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual bool GotoAzAlt(double az, double alt)
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
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.
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer() or IEAddPeriodicTimer().
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
TelescopePierSide currentPierSide
INDI::PropertyNumber TrackRateNP
INDI::PropertySwitch MovementNSSP
INDI::PropertySwitch SlewRateSP
INDI::PropertySwitch TrackModeSP
INDI::PropertyText TimeTP
INDI::PropertySwitch MountTypeSP
INDI::PropertySwitch MovementWESP
INDI::PropertyNumber LocationNP
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
double range24(double r)
range24 Limits a number to be between 0-24 range.
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
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[].
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.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sidereal time given longitude and system clock.
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number'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.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#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 TRACKRATE_SIDEREAL
void J2000toObserved(IEquatorialCoordinates *J2000pos, double jd, IEquatorialCoordinates *observed)
*J2000toObserved converts catalogue to observed
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
void ObservedToJ2000(IEquatorialCoordinates *observed, double jd, IEquatorialCoordinates *J2000pos)
ObservedToJ2000 converts an observed position to a J2000 catalogue position removes aberration,...