31#include <libnova/sidereal_time.h>
46#define SIDRATE 0.004178
48#define FIRMWARE_TAB "Firmware data"
50#define ONSTEP_TIMEOUT 3
53static std::unique_ptr<LX200_TeenAstro> teenAstro(
new LX200_TeenAstro());
70 LOG_DEBUG(
"Initializing from LX200 TeenAstro device...");
86 return "LX200 TeenAstro";
104 IUFillText(&ErrorStatusT[0],
"Error code",
"",
"");
128 IUFillNumber(&SlewAccuracyN[0],
"SlewRA",
"RA (arcmin)",
"%10.6m", 0., 60., 1., 3.0);
129 IUFillNumber(&SlewAccuracyN[1],
"SlewDEC",
"Dec (arcmin)",
"%10.6m", 0., 60., 1., 3.0);
138 IUFillSwitchVector(&SiteSP, SiteS, 4,
getDeviceName(),
"Sites",
"",
SITE_TAB,
IP_RW,
ISR_1OFMANY, 0,
IPS_IDLE);
231 LOG_ERROR(
"Error communicating with telescope.");
261 if (isSlewComplete())
264 LOG_INFO(
"Slew is complete. Tracking...");
274 if (OSStat[15] !=
'0')
276 updateMountStatus(OSStat[15]);
278 if (strcmp(OSStat, OldOSStat) != 0)
280 handleStatusChange();
281 snprintf(OldOSStat,
sizeof(OldOSStat),
"%s", OSStat);
288 currentRA += 0.000001;
306void LX200_TeenAstro::handleStatusChange(
void)
310 if (OSStat[0] != OldOSStat[0])
312 if (OSStat[0] ==
'0')
316 else if (OSStat[0] ==
'1')
320 else if (OSStat[0] ==
'2' || OSStat[0] ==
'3' )
328 if (OSStat[2] != OldOSStat[2])
330 if (OSStat[2] ==
'P')
341 if (OSStat[4] != OldOSStat[4])
348 if (OSStat[13] != OldOSStat[13])
353 if (OSStat[15] != OldOSStat[15])
355 updateMountStatus(OSStat[15]);
364void LX200_TeenAstro::updateMountStatus(
char status)
366 static const char *errCodes[9] = {
"ERR_NONE",
"ERR_MOTOR_FAULT",
"ERR_ALT",
"ERR_LIMIT_SENSE",
367 "ERR_AXIS2",
"ERR_AZM",
"ERR_UNDER_POLE",
"ERR_MERIDIAN",
"ERR_SYNC"
370 if (status <
'0' || status >
'9')
383 IUSaveText(&ErrorStatusT[0], errCodes[status -
'0']);
396 char RAStr[64] = {0}, DecStr[64] = {0};
398 fs_sexa(RAStr, targetRA, 2, 3600);
399 fs_sexa(DecStr, targetDEC, 2, 3600);
419 const struct timespec ms100_delay = {.tv_sec = 0, .tv_nsec = 100000000};
420 nanosleep(&ms100_delay, NULL);
439 LOGF_ERROR(
"Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
449 LOGF_INFO(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
453bool LX200_TeenAstro::isSlewComplete()
457 return fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0);
475 char syncString[256] = {0};
481 LOG_ERROR(
"Error setting RA/DEC. Unable to Sync.");
498 LOG_INFO(
"Synchronization successful.");
520 LOGF_WARN(
"===CMD==> Set Park Pos %s", response);
525 LOG_WARN(
"Park Value set to current position");
566 Telescope::AbortSP.apply();
569 Telescope::AbortSP.setState(
IPS_OK);
572 Telescope::AbortSP.apply();
596 LOG_INFO(
"Parking is in progress...");
614void LX200_TeenAstro::updateSlewRate()
619 if (getSlewRate(&slewRateIndex))
621 LOGF_INFO(
"current slew rate : %d", slewRateIndex);
623 SlewRateS[slewRateIndex].s =
ISS_ON;
629 LOG_ERROR(
"Error reading current slew rate");
639 int currentSiteIndex;
650 statusCommand =
":GXI#";
651 guideSpeedCommand =
":SXR0:%02d#";
657 SiteNameT[0].text =
new char[64];
660 if (getSiteIndex(¤tSiteIndex))
662 SiteS[currentSiteIndex].s =
ISS_ON;
663 currentSiteNum = currentSiteIndex + 1;
664 LOGF_INFO(
"Site number %d", currentSiteNum);
674 LOG_ERROR(
"Error reading current site number");
679 for (
unsigned i = 0; i <
sizeof(OldOSStat); i++)
682 handleStatusChange();
698 LOG_INFO(
"=============== Parkdata loaded");
703 LOG_INFO(
"=============== Parkdata Load Failed");
722 if (!strcmp(name, SlewAccuracyNP.
name))
729 if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
730 IDSetNumber(&SlewAccuracyNP,
"Warning: Setting the slew accuracy too low may result in a dead lock");
735 if (!strcmp(name, GuideRateNP.
name))
740 float guideRate = GuideRateN[0].value;
741 SetGuideRate(guideRate);
759 if (!strcmp(name, SlewRateSP.
name))
764 if (!selectSlewRate(slewRate))
766 LOGF_ERROR(
"Error setting move to rate %d.", slewRate);
776 if (!strcmp(name, SiteSP.
name))
782 LOGF_DEBUG(
"currentSiteNum: %d", currentSiteNum);
801 LOGF_INFO(
"Setting site number %d", currentSiteNum);
802 SiteS[currentSiteNum - 1].s =
ISS_ON;
820 if (!strcmp(name, SiteNameTP.
name))
845bool LX200_TeenAstro::getLocalDate(
char *dateString)
849 time_t now = time(
nullptr);
850 strftime(dateString,
MAXINDINAME,
"%F", localtime(&now));
860bool LX200_TeenAstro::setLocalDate(uint8_t days, uint8_t months, uint16_t years)
865bool LX200_TeenAstro::getLocalTime(
char *timeString)
869 time_t now = time(
nullptr);
870 strftime(timeString,
MAXINDINAME,
"%T", localtime(&now));
878 snprintf(timeString,
MAXINDINAME,
"%02d:%02d:%02d", h, m, s);
885bool LX200_TeenAstro::getUTFOffset(
double *offset)
893 int lx200_utc_offset = 0;
897 *offset = lx200_utc_offset * -1;
901bool LX200_TeenAstro::sendScopeTime()
909 memset(<m, 0,
sizeof(ltm));
910 memset(&utm, 0,
sizeof(utm));
914 if (getUTFOffset(&offset))
916 char utcStr[8] = {0};
917 snprintf(utcStr,
sizeof(utcStr),
"%.2f", offset);
922 LOG_WARN(
"Could not obtain UTC offset from mount!");
926 if (getLocalTime(ctime) ==
false)
928 LOG_WARN(
"Could not obtain local time from mount!");
932 if (getLocalDate(cdate) ==
false)
934 LOG_WARN(
"Could not obtain local date from mount!");
940 snprintf(datetime,
MAXINDINAME,
"%sT%s", cdate, ctime);
943 if (strptime(datetime,
"%FT%T", <m) ==
nullptr)
945 LOGF_WARN(
"Could not process mount date and time: %s", datetime);
951 time_epoch = mktime(<m);
954 time_epoch -=
static_cast<int>(offset * 3600.0);
957 localtime_r(&time_epoch, &utm);
960 strftime(cdate,
MAXINDINAME,
"%Y-%m-%dT%H:%M:%S", &utm);
976bool LX200_TeenAstro::sendScopeLocation()
978 int dd = 0, mm = 0, elev = 0;
996 LOG_WARN(
"Failed to get site latitude from device.");
1008 LOG_WARN(
"Failed to get site longitude from device.");
1021 if (getSiteElevation(&elev))
1027 LOG_ERROR(
"Error getting site elevation");
1038bool LX200_TeenAstro::getSiteElevation(
int *elevationP)
1048bool LX200_TeenAstro::getSiteIndex(
int *ndxP)
1059bool LX200_TeenAstro::getSlewRate(
int *ndxP)
1061 unsigned char rate = (OSStat[4] -
'0');
1071bool LX200_TeenAstro::setSite(
int num)
1074 snprintf (buf,
sizeof(buf),
":W%d#", num - 1);
1082bool LX200_TeenAstro::setSiteElevation(
double elevation)
1085 snprintf (buf,
sizeof(buf),
":Se%+4d#",
static_cast<int>(elevation));
1095bool LX200_TeenAstro::getLocation()
1097 int dd = 0, mm = 0, elev = 0;
1102 LOG_WARN(
"Failed to get site latitude from device.");
1115 LOG_WARN(
"Failed to get site longitude from device.");
1125 if (getSiteElevation(&elev))
1131 LOG_ERROR(
"Error getting site elevation");
1141bool LX200_TeenAstro::SetGuideRate(
float guideRate)
1145 snprintf (cmdString,
sizeof(cmdString), guideSpeedCommand, (
int) (guideRate * 100));
1146 sendCommand(cmdString);
1167 GuideNSTID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperNS,
this);
1183 GuideNSTID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperNS,
this);
1199 GuideWETID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperWE,
this);
1215 GuideWETID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperWE,
this);
1219void LX200_TeenAstro::SendPulseCmd(int8_t direction, uint32_t duration_msec)
1265bool LX200_TeenAstro::Move(
TDirection dir, TelescopeMotionCommand
cmd)
1294void LX200_TeenAstro::mountSim()
1296 static struct timeval ltv;
1302 gettimeofday(&tv,
nullptr);
1304 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1307 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1360void LX200_TeenAstro::slewError(
int slewCode)
1369 else if (slewCode == 2)
1371 LOG_INFO(
"Object below the minimum elevation limit.");
1389 sendCommand(
":Te#");
1393 sendCommand(
":Td#");
1401bool LX200_TeenAstro::selectSlewRate(
int index)
1405 snprintf(
cmd,
sizeof(
cmd),
":R%d#", index);
1415void LX200_TeenAstro::sendCommand(
const char *
cmd)
1426void LX200_TeenAstro::guideTimeoutHelperNS(
void * p)
1431void LX200_TeenAstro::guideTimeoutHelperWE(
void * p)
1436void LX200_TeenAstro::guideTimeoutNS()
1445void LX200_TeenAstro::guideTimeoutWE()
INDI::PropertyText getText(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
INDI::PropertyNumber GuideNSNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INDI::PropertyNumber GuideWENP
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
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
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.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
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.
@ TELESCOPE_HAS_PIER_SIDE
@ 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)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
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.
virtual const char * getDriverName() override
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 MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
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 ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool Handshake() override
perform handshake with device to check communication
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual const char * getDefaultName() override
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool Park() override
Park the telescope to its home position.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void getBasicData()
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
Class to provide general functionality of a telescope device.
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.
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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.
INDI::PropertySwitch ParkSP
INDI::PropertySwitch AbortSP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertyText TimeTP
INDI::PropertySwitch MovementWESP
INDI::PropertySwitch ParkOptionSP
INDI::PropertyNumber LocationNP
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
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 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[].
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
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.
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 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.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
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.
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,...)
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,...)
std::mutex lx200CommsLock
#define INITIAL_GUIDE_RATE
std::mutex lx200CommsLock
int SendPulseCmd(int fd, int direction, int duration_msec, bool wait_after_command, int max_wait_ms)
int getSiteLongitude(int fd, int *ddd, int *mm, double *ssf)
int selectTrackingMode(int fd, int trackMode)
int getSiteName(int fd, char *siteName, int siteNum)
int getCommandInt(int fd, int *value, const char *cmd)
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 MoveTo(int fd, int direction)
int setSiteName(int fd, char *siteName, int siteNum)
void setLX200Debug(const char *deviceName, unsigned int debug_level)
int HaltMovement(int fd, int direction)
int getCommandString(int fd, char *data, const char *cmd)
int getSiteLatitude(int fd, int *dd, int *mm, double *ssf)
#define getUTCOffset(fd, x)
#define getVersionDate(fd, x)
#define getVersionTime(fd, x)
#define getLX200DEC(fd, x)
#define getVersionNumber(fd, x)
#define getLX200RA(fd, x)
#define getProductName(fd, x)
#define getLocalTime24(fd, x)
Namespace to encapsulate INDI client, drivers, and mediator classes.
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.