30 #define PRODUCT_NAME "TitanTCS CRUX"
31 #define HANDSHAKE_NAME "TiTaN TCS"
32 #define MIN_FW_VERSION "3.1.0"
33 #define MAX_CMD_LEN 256
35 static std::unique_ptr<TitanTCS> titanTCS(
new TitanTCS());
68 bool bResult = Telescope::Connect();
69 LOGF_DEBUG(
"Connect() => %s", (bResult ?
"true" :
"false"));
83 bool bResult = Telescope::Disconnect();
84 LOGF_DEBUG(
"Disconnect() => %s", (bResult ?
"true" :
"false"));
118 IUFillText(&PECInfoT[0],
"PEC_INFO",
"PEC",
"");
119 IUFillText(&PECInfoT[1],
"PEC_TR_INFO",
"Training",
"");
124 IUFillText(&MountInfoT[0],
"MOUNT_PARK",
"Park",
"");
125 IUFillText(&MountInfoT[1],
"MOUNT_TRACKING",
"Tracking",
"");
213 else if(nowIndex == 1)
216 if(CommandResponse(
"#:hP?#",
"$hP",
'#', NULL, &iVal))
246 SendCommand(
"#:\\e10#:\\e11#");
248 else if(nowIndex == 1)
250 SendCommand(
"#:\\e12#");
255 if (!strcmp(name, PECTrainingSP.
name))
265 SendCommand(
"#:\\e20#:\\e21#");
267 else if(nowIndex == 1)
269 SendCommand(
"#:\\e23#");
286 else if(nowIndex == 1)
324 if(CommandResponseStr(
"#:GVP#",
"",
'#', szResponse,
sizeof(szResponse)))
326 LOGF_INFO(
"Product Name = '%s'", szResponse);
329 if(CommandResponseStr(
"#:GVN#",
"",
'#', szResponse,
sizeof(szResponse)))
331 LOGF_INFO(
"Firmware Version = '%s'", szResponse);
342 LOG_ERROR(
"The firmware version cannot be read.");
347 LOGF_ERROR(
"TitanTCS could not be found. return code = '%s'", szResponse);
357 static int Char2Num(
char chr)
359 if((chr >=
'0') && (chr <=
'9'))
362 if((chr >=
'A') && (chr <=
'F'))
363 return chr -
'A' + 10;
365 if((chr >=
'a') && (chr <=
'f'))
366 return chr -
'a' + 10;
371 static int GetDigitParam(
const char *pStr,
int* pDigit,
char* pDelimeter =
nullptr)
382 while (*pStr ==
' ' || *pStr ==
'+')
397 pDigit[cntParam] = sign;
399 pDelimeter[cntParam] = 0;
402 for(i = 0; i < 3; i++)
404 pDigit[cntParam] = 0;
418 pDelimeter[cntParam] = *pStr;
422 pDigit[cntParam] *= 10;
423 pDigit[cntParam] += Char2Num(*pStr);
443 static bool HMS2Hour(
const char* pStr,
double* hr)
445 int digit[5] = { 0, 0, 0, 0, 0 };
446 int rtnCode = GetDigitParam(pStr, digit);
449 for(
int i = 1; i < 4; i++)
462 static void formatRA(
long secRa,
char* pStr)
471 int h = secRa / 3600;
480 sprintf(pStr,
"-%02d:%02d:%02d", h, m, s);
482 sprintf(pStr,
"%02d:%02d:%02d", h, m, s);
485 static void formatDEC(
long secDec,
char* pStr)
487 if (secDec > (270 * 3600))
488 secDec = secDec - (360 * 3600);
489 else if (secDec > (90 * 3600))
490 secDec = (180 * 3600) - secDec;
503 int h = secDec / 3600;
504 secDec -= (h * 3600);
511 sprintf(pStr,
"%c%02d*%02d:%02d", sign, h, m, s);
519 SendCommand(
":Mgn%d#", (
int)ms);
530 GuideNSTID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperNS,
this);
536 SendCommand(
":Mgs%d#", (
int)ms);
547 GuideNSTID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperNS,
this);
553 SendCommand(
":Mge%d#", (
int)ms);
564 GuideWETID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperWE,
this);
570 SendCommand(
":Mgw%d#", (
int)ms);
581 GuideWETID =
IEAddTimer(
static_cast<int>(ms), guideTimeoutHelperWE,
this);
598 if(!SetTarget(
ra,
dec))
603 sprintf(szCommand,
":MS#");
605 if(!CommandResponseChar(szCommand,
"", &rtnCode))
612 LOGF_ERROR(
"Goto / Error Code = '%c'", rtnCode);
631 return SendCommand(
"#:Q#");
647 bool TitanTCS::GetParamStr(
const char* pInStr,
char* pOutStr,
int len,
const char* pResponse,
char delimeter)
651 if((pResponse != NULL) && (*pResponse == 0))
656 const char* pFind = strstr(pInStr, pResponse);
662 int l = strlen(pResponse);
670 for(
int i = 0; i < 3; i++)
684 strncpy(pOutStr, pInStr, len);
688 char* pDel = strchr(pOutStr, delimeter);
703 bool TitanTCS::GetParamNumber(
const char* pInStr,
char* pOutStr,
int len,
const char* pResponse,
char delimeter,
704 double *pDouble,
int *pInteger)
706 if(!GetParamStr(pInStr, pOutStr, len, pResponse, delimeter))
710 *pDouble = atof(pOutStr);
712 *pInteger = atoi(pOutStr);
717 bool TitanTCS::GetParamHour(
const char* pInStr,
char* pOutStr,
int len,
const char* pResponse,
char delimeter,
720 if(!GetParamStr(pInStr, pOutStr, len, pResponse, delimeter))
724 if(HMS2Hour(pOutStr, pHour))
731 bool TitanTCS::SendCommand(
const char *
cmd)
739 int nbytes_written = 0;
744 char titanfocus_error[256];
746 LOGF_ERROR(
"tty_write() error detected: %s", titanfocus_error);
755 bool TitanTCS::SendCommand(
const char *
cmd,
int val)
758 sprintf(szBuff,
cmd, val);
760 return SendCommand(szBuff);
763 bool TitanTCS::SendCommand(
const char *
cmd,
double val)
766 sprintf(szBuff,
cmd, val);
768 return SendCommand(szBuff);
771 void TitanTCS::ReadFlush()
781 for(
int i = 0; i < 3; i++)
796 int TitanTCS::ReadResponse(
char *buf,
int len,
char delimeter,
int timeout)
807 for(
int i = 0; i < len; i++)
809 int err_code =
tty_read(
PortFD, buf + recv_len, 1, timeout, &bytesRead);
815 char titanfocus_error[256] = {0};
817 LOGF_ERROR(
"tty_read() error detected: '%s' len %d, %s", buf, recv_len, titanfocus_error);
821 char read_ch = buf[recv_len];
834 if((recv_len + 1) >= len)
836 LOGF_ERROR(
"TTY error detected: overflow %d, %d", recv_len, len);
843 if(read_ch == delimeter)
853 bool TitanTCS::CommandResponse(
const char* pCommand,
const char* pResponse,
char delimeter,
double *pDouble,
int *pInteger)
856 if (!SendCommand(pCommand))
862 int rd_count = ReadResponse(szResponse,
sizeof(szResponse), delimeter);
870 if(!GetParamNumber(szResponse, szResult,
sizeof(szResult) - 1, pResponse, delimeter, pDouble, pInteger))
872 LOGF_DEBUG(
"CommandResponse('%s', '%s') Fail!", pCommand, pResponse);
879 bool TitanTCS::CommandResponseHour(
const char* pCommand,
const char* pResponse,
char delimeter,
double* Hour)
882 if (!SendCommand(pCommand))
888 int rd_count = ReadResponse(szResponse,
sizeof(szResponse), delimeter);
896 if(!GetParamHour(szResponse, szResult,
sizeof(szResult) - 1, pResponse, delimeter, Hour))
898 LOGF_DEBUG(
"CommandResponseHour('%s', '%s') Fail!", pCommand, pResponse);
905 bool TitanTCS::CommandResponseStr(
const char* pCommand,
const char* pResponse,
char delimeter,
char* pReturn,
int len)
908 if (!SendCommand(pCommand))
913 int rd_count = ReadResponse(szResponse,
sizeof(szResponse), delimeter);
921 if(!GetParamStr(szResponse, pReturn, len, pResponse, delimeter))
923 LOGF_DEBUG(
"CommandResponseStr('%s', '%s') Fail!", pCommand, pResponse);
932 bool TitanTCS::CommandResponseChar(
const char* pCommand,
const char* pResponse,
char* pReturn)
935 if (!SendCommand(pCommand))
941 int rd_count = ReadResponse(szResponse, 1, 0);
949 if(!GetParamStr(szResponse, szResult,
sizeof(szResult) - 1, pResponse, 0))
951 LOGF_DEBUG(
"CommandResponseChar('%s', '%s') Fail!", pCommand, pResponse);
955 *pReturn = szResult[0];
962 bool TitanTCS::SetTarget(
double ra,
double dec)
965 formatRA(
ra * 3600, szRA);
966 formatDEC(
dec * 3600, szDEC);
971 sprintf(szCommand,
"#:Sr %s#", szRA);
972 if(!CommandResponseChar(szCommand,
"", &rtnCode))
979 LOGF_ERROR(
"SetTarget DEC / Error Code = '%c'", rtnCode);
983 sprintf(szCommand,
"#:Sd %s#", szDEC);
984 if(!CommandResponseChar(szCommand,
"", &rtnCode))
986 LOG_ERROR(
"SetTarget DEC / No response");
991 LOGF_ERROR(
"SetTarget DEC / Error Code = '%c'", rtnCode);
995 LOGF_INFO(
"Set target RA:%s, DEC:%s", szRA, szDEC);
999 void TitanTCS::guideTimeoutNS()
1008 void TitanTCS::guideTimeoutWE()
1017 void TitanTCS::guideTimeoutHelperNS(
void * p)
1019 static_cast<TitanTCS *
>(p)->guideTimeoutNS();
1022 void TitanTCS::guideTimeoutHelperWE(
void * p)
1024 static_cast<TitanTCS *
>(p)->guideTimeoutWE();
1027 bool TitanTCS::GetMountParams(
bool bAll)
1033 char szCommand[256];
1034 sprintf(szCommand,
"#:\\GE($GR #:GR#"
1041 ":\\GE%d)#", cnt++);
1045 char szResponse[256];
1046 if(!CommandResponseStr(szCommand,
"(",
')', szResponse,
sizeof(szResponse) - 1))
1051 if(GetParamHour(szResponse, szToken,
sizeof(szToken) - 1,
"$GR",
'#', &info.
ra))
1053 if(GetParamHour(szResponse, szToken,
sizeof(szToken) - 1,
"$GD",
'#', &info.
dec))
1062 if(GetParamNumber(szResponse, szToken,
sizeof(szToken) - 1,
"$?pe",
'#', NULL, &info.
PECStatus))
1070 if(GetParamNumber(szResponse, szToken,
sizeof(szToken) - 1,
"$?ts",
'#', NULL, &info.
TrackingStatus))
1088 if(GetParamNumber(szResponse, szToken,
sizeof(szToken) - 1,
"$hP",
'#', NULL, &info.
Parking))
1135 if(GetParamNumber(szResponse, szToken,
sizeof(szToken) - 1,
"$?tm",
'#', NULL, &info.
Landscape))
1146 IUSaveText(&MountInfoT[1],
"Tracking ON / Skyview");
1156 IUSaveText(&MountInfoT[1],
"Tracking OFF / Landscape");
1158 IUSaveText(&MountInfoT[1],
"Tracking OFF / Idle");
1166 if(GetParamNumber(szResponse, szToken,
sizeof(szToken) - 1,
"$?tr",
'#', NULL, &info.
TrackingRate))
1176 static int prev_TrackState = -1;
1190 LOG_INFO(
"Track State : TRACKING");
1204 void TitanTCS::_setPECState(
int pec_status)
1206 if (_PECStatus != pec_status)
1211 _PECStatus = pec_status;
1217 if(pec_status & 0x30)
1221 PECTrainingS[1].s =
ISS_ON;
1223 sprintf(szText,
"PEC Training %d %%", (pec_status >> 8));
1228 PECTrainingS[0].s =
ISS_ON;
1249 IUSaveText(&PECInfoT[0],
"PEC is available.");
1260 if(pec_status & 0x30)
1263 IUSaveText(&PECInfoT[0],
"PEC training is required.");
1286 double JD = ln_get_julian_day(utc);
1290 ln_date_to_zonedate(utc, <m, utc_offset * 3600);
1292 LOGF_DEBUG(
"Local time is %02d:%02d:%02g", ltm.hours, ltm.minutes, ltm.seconds);
1295 sprintf(szText,
"#:SG %.1f#:SC %02d/%02d/%02d#:SL %02d:%02d:%02d#",
1297 ltm.months, ltm.days, ltm.years % 100,
1298 ltm.hours, ltm.minutes, (
int)ltm.seconds % 60);
1302 return SendCommand(szText);
1310 if((fabs(latitude) < 0.001) && (fabs(longitude) < 0.001))
1313 int d = 0, m = 0, s = 0;
1314 char szCommand[128];
1318 sprintf(szCommand,
"#:St %03d:%02d:%02d#", d, m, s);
1319 LOGF_INFO(
"Set latitude '%s'", szCommand);
1320 if(!CommandResponseChar(szCommand, NULL, &rtnCode))
1324 sprintf(szCommand,
"#:Sg %03d:%02d:%02d#", d, m, s);
1325 LOGF_INFO(
"Set longitude '%s'", szCommand);
1326 return CommandResponseChar(szCommand, NULL, &rtnCode);
1331 if(!SetTarget(
ra,
dec))
1334 char rtnCode[64] = {
"" };
1336 sprintf(szCommand,
":CM#");
1338 if(!CommandResponseStr(szCommand,
"",
'#', rtnCode,
sizeof(rtnCode) - 1))
1343 if(strcmp(rtnCode,
"1") != 0)
1345 LOGF_ERROR(
"Sync / Error Code = '%s'", rtnCode);
1373 sprintf(szCommand,
":M%c#", chDir);
1377 sprintf(szCommand,
":Q%c#", chDir);
1381 LOGF_INFO(
"Moving command:%s", szCommand);
1382 return SendCommand(szCommand);
1406 sprintf(szCommand,
":M%c#", chDir);
1410 sprintf(szCommand,
":Q%c#", chDir);
1414 LOGF_INFO(
"Moving command:%s", szCommand);
1415 return SendCommand(szCommand);
1422 if(SendCommand(
":hP8#"))
1435 if(SendCommand(
":hP0#"))
1448 return SendCommand(
"#:\\T%d#", mode);
1464 return SendCommand(
"#:\\t0#");
1469 return SendCommand(
"#:\\t1#");
1499 return SendCommand(
":RS#");
1501 return SendCommand(
":RM#");
1503 return SendCommand(
":RC#");
1505 return SendCommand(
":RG#");
const char * getDeviceName() const
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 setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
uint16_t getDriverInterface() const
void addDebugControl()
Add Debug control to the driver.
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
TelescopeStatus TrackState
ISwitchVectorProperty TrackStateSP
ISwitchVectorProperty MovementNSSP
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.
ISwitchVectorProperty PECStateSP
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
ISwitchVectorProperty TrackModeSP
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
ISwitchVectorProperty ParkSP
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
ISwitchVectorProperty MovementWESP
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 bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool Disconnect() override
Disconnect from device.
virtual bool Park() override
Park the telescope to its home position.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool ISNewText(const char *dev, const char *name, char **texts, char **names, int n) override
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
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 SetParkPosition(double Axis1Value, double Axis2Value) override
SetParkPosition Set desired parking position to the supplied value. This ONLY sets the desired park p...
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual const char * getDefaultName() override
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool Goto(double ra, double dec) override
Move the scope to the supplied RA and DEC coordinates.
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.
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.
Implementations for common driver routines.
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 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 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,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(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,...)