Instrument Neutral Distributed Interface INDI  2.0.2
crux_mount.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Driver type: TitanTCS for HOBYM CRUX Mount INDI Driver
3 
4  Copyright(c) 2020 Park Suyoung <hparksy@gmail.com>. All rights reserved.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9  .
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14  .
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 *******************************************************************************/
20 
21 #include <cstring>
22 
23 #include "crux_mount.h"
24 
25 #include "indicom.h"
26 
27 #include <cmath>
28 #include <memory>
29 
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
34 
35 static std::unique_ptr<TitanTCS> titanTCS(new TitanTCS());
36 
38 {
39  setVersion(1, 0);
40 
48  //TELESCOPE_HAS_PIER_SIDE |
49 #if USE_PEC
51 #endif
54  //TELESCOPE_HAS_TRACK_RATE
55  , 4);
56 
58 
59  LOG_INFO("Initializing from " PRODUCT_NAME " device...");
60 
61  m_Connect = 0;
62 }
63 
65 {
66  m_Connect = 1;
67 
68  bool bResult = Telescope::Connect();
69  LOGF_DEBUG("Connect() => %s", (bResult ? "true" : "false"));
70 
71  if(bResult)
72  m_Connect = 2;
73  else
74  m_Connect = -1;
75 
76  return bResult;
77 }
78 
80 {
81  m_Connect = 0;
82 
83  bool bResult = Telescope::Disconnect();
84  LOGF_DEBUG("Disconnect() => %s", (bResult ? "true" : "false"));
85 
86  return bResult;
87 }
88 
89 /**************************************************************************************
90 ** We init our properties here. The only thing we want to init are the Debug controls
91 ***************************************************************************************/
93 {
94 #if USE_PEC
95  _PECStatus = -1;
96 #endif
97  //
99 
102 
103  AddTrackMode("TRACK_SIDEREAL", "Sidereal");
104  AddTrackMode("TRACK_SOLAR", "Solar");
105  AddTrackMode("TRACK_LUNAR", "Lunar");
106 
107  addDebugControl();
108 
109 #if USE_PEC
110  // PEC Training
111  IUFillSwitch(&PECTrainingS[0], "PEC_Start", "Start", ISS_OFF);
112  IUFillSwitch(&PECTrainingS[1], "PEC_Stop", "Stop", ISS_OFF);
113  IUFillSwitchVector(&PECTrainingSP, PECTrainingS, 2, getDeviceName(), "PEC_TRAINING", "PEC Training", MOTION_TAB, IP_RW,
114  ISR_1OFMANY, 0,
115  IPS_IDLE);
116 
117  // PEC Details
118  IUFillText(&PECInfoT[0], "PEC_INFO", "PEC", "");
119  IUFillText(&PECInfoT[1], "PEC_TR_INFO", "Training", "");
120  IUFillTextVector(&PECInfoTP, PECInfoT, 2, getDeviceName(), "PEC_INFOS", "PEC Info", MOTION_TAB,
121  IP_RO, 60, IPS_IDLE);
122 #endif
123  // Mount Details
124  IUFillText(&MountInfoT[0], "MOUNT_PARK", "Park", "");
125  IUFillText(&MountInfoT[1], "MOUNT_TRACKING", "Tracking", "");
126  IUFillTextVector(&MountInfoTP, MountInfoT, 2, getDeviceName(), "MOUNT_INFOS", "Mount Info", MAIN_CONTROL_TAB,
127  IP_RO, 60, IPS_IDLE);
128 
130 
131  return true;
132 }
133 
134 
136 {
138 
139  if (isConnected())
140  {
141 #if USE_PEC
142  defineProperty(&PECTrainingSP);
143  defineProperty(&PECInfoTP);
144 #endif
145  defineProperty(&MountInfoTP);
146  //
149  //
153  //
154  GetMountParams();
155  }
156  else
157  {
158 #if USE_PEC
159  deleteProperty(PECTrainingSP.name);
160  deleteProperty(PECInfoTP.name);
161 #endif
162  deleteProperty(MountInfoTP.name);
163  //
166  }
167 
168  return true;
169 }
170 
171 bool TitanTCS::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
172 {
173  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
174  {
175  /*
176  if (strcmp(name, "JOG_RATE") == 0) {
177  IUUpdateNumber(&JogRateNP, values, names, n);
178  JogRateNP.s = IPS_OK;
179  IDSetNumber(&JogRateNP, nullptr);
180  return true;
181  }
182  if (strcmp(name, GuideRateNP.name) == 0) {
183  IUUpdateNumber(&GuideRateNP, values, names, n);
184  GuideRateNP.s = IPS_OK;
185  IDSetNumber(&GuideRateNP, nullptr);
186  return true;
187  }
188  */
189  if (strcmp(name, GuideNSNP.name) == 0 || strcmp(name, GuideWENP.name) == 0)
190  {
191  LOGF_DEBUG("%s = %g", name, values[0]);
192  processGuiderProperties(name, values, names, n);
193  return true;
194  }
195  }
196 
197  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
198 }
199 
200 bool TitanTCS::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
201 {
202  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
203  {
204  int iVal = 0;
205  // ---------------------------------------------------------------------
206  // Park $$$
207  if (!strcmp(name, ParkSP.name))
208  {
209  IUUpdateSwitch(&ParkSP, states, names, n);
210  int nowIndex = IUFindOnSwitchIndex(&ParkSP);
211  if(nowIndex == 0)
212  Park();
213  else if(nowIndex == 1)
214  UnPark();
215 
216  if(CommandResponse("#:hP?#", "$hP", '#', NULL, &iVal))
217  {
219  {
220  if(iVal == 2)
222  else if(iVal == 0)
224  }
225  else if(TrackState == SCOPE_PARKED)
226  {
227  if(iVal == 0)
229  }
230  }
231 
232  return true;
233  }
234  //
235 #if USE_PEC
236  if (!strcmp(name, PECStateSP.name))
237  {
238  //int preIndex = IUFindOnSwitchIndex(&PECStateSP);
239  IUUpdateSwitch(&PECStateSP, states, names, n);
240  int nowIndex = IUFindOnSwitchIndex(&PECStateSP);
241 
242  IDSetSwitch(&PECStateSP, nullptr);
243 
244  if(nowIndex == 0)
245  {
246  SendCommand("#:\\e10#:\\e11#");
247  }
248  else if(nowIndex == 1)
249  {
250  SendCommand("#:\\e12#");
251  }
252  return true;
253  }
254  //
255  if (!strcmp(name, PECTrainingSP.name))
256  {
257  //int preIndex = IUFindOnSwitchIndex(&PECTrainingSP);
258  IUUpdateSwitch(&PECTrainingSP, states, names, n);
259  int nowIndex = IUFindOnSwitchIndex(&PECTrainingSP);
260 
261  IDSetSwitch(&PECTrainingSP, nullptr);
262 
263  if(nowIndex == 0)
264  {
265  SendCommand("#:\\e20#:\\e21#");
266  }
267  else if(nowIndex == 1)
268  {
269  SendCommand("#:\\e23#");
270  }
271  return true;
272  }
273 #endif
274  //
275  if (!strcmp(name, TrackStateSP.name))
276  {
277  IUUpdateSwitch(&TrackStateSP, states, names, n);
278  int nowIndex = IUFindOnSwitchIndex(&TrackStateSP);
279 
280  IDSetSwitch(&TrackStateSP, nullptr);
281 
282  if(nowIndex == 0)
283  {
284  SetTrackEnabled(true);
285  }
286  else if(nowIndex == 1)
287  {
288  SetTrackEnabled(false);
289  }
290  return true;
291  }
292  //
293  if (!strcmp(name, TrackModeSP.name))
294  {
295  IUUpdateSwitch(&TrackModeSP, states, names, n);
296  int nowIndex = IUFindOnSwitchIndex(&TrackModeSP);
297 
298  IDSetSwitch(&TrackModeSP, nullptr);
299 
300  SetTrackMode(nowIndex);
301 
302  return true;
303  }
304  }
305 
306  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
307 }
308 
309 bool TitanTCS::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
310 {
311  return INDI::Telescope::ISNewText(dev, name, texts, names, n);
312 }
313 
314 /**************************************************************************************
315 ** INDI is asking us to check communication with the device via a handshake
316 ***************************************************************************************/
318 {
319  if(!isConnected())
320  return true;
321 
322  char szResponse[MAX_CMD_LEN] = { 0 };
323 
324  if(CommandResponseStr("#:GVP#", "", '#', szResponse, sizeof(szResponse)))
325  {
326  LOGF_INFO("Product Name = '%s'", szResponse);
327  if(strstr(szResponse, HANDSHAKE_NAME))
328  {
329  if(CommandResponseStr("#:GVN#", "", '#', szResponse, sizeof(szResponse)))
330  {
331  LOGF_INFO("Firmware Version = '%s'", szResponse);
332  int comp = strcmp(szResponse, MIN_FW_VERSION);
333  if(comp >= 0)
334  return true;
335  else
336  {
337  LOGF_ERROR("Firmware version '%s' is too old. Required > %s", szResponse, MIN_FW_VERSION);
338  }
339  }
340  else
341  {
342  LOG_ERROR("The firmware version cannot be read.");
343  }
344  }
345  else
346  {
347  LOGF_ERROR("TitanTCS could not be found. return code = '%s'", szResponse);
348  }
349  }
350 
351  LOG_ERROR("Handshake() failed!");
352 
353  //Disconnect();
354  return false;
355 }
356 
357 static int Char2Num(char chr)
358 {
359  if((chr >= '0') && (chr <= '9'))
360  return chr - '0';
361 
362  if((chr >= 'A') && (chr <= 'F'))
363  return chr - 'A' + 10;
364 
365  if((chr >= 'a') && (chr <= 'f'))
366  return chr - 'a' + 10;
367 
368  return 0;
369 }
370 
371 static int GetDigitParam(const char *pStr, int* pDigit, char* pDelimeter = nullptr)
372 {
373  /*
374  HH:MM.T#
375  HH:MM:SS#
376  */
377 
378  int cntParam = 0;
379  short sign = 1;
380  int i, chrCnt;
381 
382  while (*pStr == ' ' || *pStr == '+')
383  {
384  ++pStr;
385  if(*pStr == 0)
386  {
387  return 0;
388  }
389  }
390 
391  if (*pStr == '-')
392  {
393  sign = -1;
394  ++pStr;
395  }
396 
397  pDigit[cntParam] = sign;
398  if(pDelimeter)
399  pDelimeter[cntParam] = 0;
400  cntParam++;
401 
402  for(i = 0; i < 3; i++)
403  {
404  pDigit[cntParam] = 0;
405  chrCnt = 0;
406  for(;;)
407  {
408  if(*pStr == 0)
409  {
410  if(chrCnt > 0)
411  cntParam++;
412  return cntParam;
413  }
414 
415  if(!isdigit(*pStr))
416  {
417  if(pDelimeter)
418  pDelimeter[cntParam] = *pStr;
419  break;
420  }
421 
422  pDigit[cntParam] *= 10;
423  pDigit[cntParam] += Char2Num(*pStr);
424 
425  chrCnt++;
426  pStr++;
427  }
428  cntParam++;
429 
430  if(*pStr == 0)
431  return cntParam;
432 
433  if(!isdigit(*pStr))
434  {
435  pStr++;
436  }
437  }
438 
439  return cntParam;
440 }
441 
442 // 00:02:43
443 static bool HMS2Hour(const char* pStr, double* hr)
444 {
445  int digit[5] = { 0, 0, 0, 0, 0 };
446  int rtnCode = GetDigitParam(pStr, digit);
447 
448  int sec = 0;
449  for(int i = 1; i < 4; i++)
450  {
451  sec *= 60;
452  sec += digit[i];
453  }
454 
455  if(digit[0] < 0)
456  sec = -sec;
457 
458  *hr = sec / 3600.0;
459  return rtnCode >= 3;
460 }
461 
462 static void formatRA(long secRa, char* pStr)
463 {
464  int sign = 1;
465  if(secRa < 0)
466  {
467  sign = -1;
468  secRa = -secRa;
469  }
470 
471  int h = secRa / 3600;
472  secRa -= (h * 3600);
473 
474  int m = secRa / 60;
475  secRa -= (m * 60);
476 
477  int s = secRa;
478 
479  if(sign < 0)
480  sprintf(pStr, "-%02d:%02d:%02d", h, m, s);
481  else
482  sprintf(pStr, "%02d:%02d:%02d", h, m, s);
483 }
484 
485 static void formatDEC(long secDec, char* pStr)
486 {
487  if (secDec > (270 * 3600))
488  secDec = secDec - (360 * 3600);
489  else if (secDec > (90 * 3600))
490  secDec = (180 * 3600) - secDec;
491 
492  char sign;
493  if (secDec >= 0)
494  {
495  sign = '+';
496  }
497  else
498  {
499  sign = '-';
500  secDec = -secDec;
501  }
502 
503  int h = secDec / 3600;
504  secDec -= (h * 3600);
505 
506  int m = secDec / 60;
507  secDec -= (m * 60);
508 
509  int s = secDec;
510 
511  sprintf(pStr, "%c%02d*%02d:%02d", sign, h, m, s);
512 }
513 
514 /**************************************************************************************
515 ** Guiding
516 ***************************************************************************************/
518 {
519  SendCommand(":Mgn%d#", (int)ms);
520  //
521  if(MovementNSSP.s == IPS_BUSY)
522  return IPS_ALERT;
523 
524  if (GuideNSTID)
525  {
526  IERmTimer(GuideNSTID);
527  GuideNSTID = 0;
528  }
529 
530  GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperNS, this);
531  return IPS_BUSY;
532 }
533 
535 {
536  SendCommand(":Mgs%d#", (int)ms);
537  //
538  if(MovementNSSP.s == IPS_BUSY)
539  return IPS_ALERT;
540 
541  if (GuideNSTID)
542  {
543  IERmTimer(GuideNSTID);
544  GuideNSTID = 0;
545  }
546 
547  GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperNS, this);
548  return IPS_BUSY;
549 }
550 
552 {
553  SendCommand(":Mge%d#", (int)ms);
554  //
555  if(MovementWESP.s == IPS_BUSY)
556  return IPS_ALERT;
557 
558  if (GuideWETID)
559  {
560  IERmTimer(GuideWETID);
561  GuideWETID = 0;
562  }
563 
564  GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperWE, this);
565  return IPS_BUSY;
566 }
567 
569 {
570  SendCommand(":Mgw%d#", (int)ms);
571  //
572  if(MovementWESP.s == IPS_BUSY)
573  return IPS_ALERT;
574 
575  if (GuideWETID)
576  {
577  IERmTimer(GuideWETID);
578  GuideWETID = 0;
579  }
580 
581  GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperWE, this);
582  return IPS_BUSY;
583 }
584 
585 /**************************************************************************************
586 ** INDI is asking us for our default device name
587 ***************************************************************************************/
589 {
590  return PRODUCT_NAME;
591 }
592 
593 /**************************************************************************************
594 ** Client is asking us to slew to a new position
595 ***************************************************************************************/
596 bool TitanTCS::Goto(double ra, double dec)
597 {
598  if(!SetTarget(ra, dec))
599  return false;
600 
601  char rtnCode;
602  char szCommand[MAX_CMD_LEN];
603  sprintf(szCommand, ":MS#");
604 
605  if(!CommandResponseChar(szCommand, "", &rtnCode))
606  {
607  LOG_ERROR("Goto / No response");
608  return false;
609  }
610  if(rtnCode != '0')
611  {
612  LOGF_ERROR("Goto / Error Code = '%c'", rtnCode);
613  return false;
614  }
615 
617 
618  LOG_INFO("Slewing ...");
619  return true;
620 }
621 
622 /**************************************************************************************
623 ** Client is asking us to abort our motion
624 ***************************************************************************************/
626 {
628  UnPark();
629 
630  LOG_DEBUG("Abort()");
631  return SendCommand("#:Q#");
632 }
633 
634 /**************************************************************************************
635 ** Client is asking us to report telescope status
636 ***************************************************************************************/
638 {
639  LOGF_DEBUG("ReadScopeStatus(s %d)", TrackState);
640 
641  GetMountParams();
642 
643  return true;
644 }
645 
646 //------------------------------------------------------------------------------
647 bool TitanTCS::GetParamStr(const char* pInStr, char* pOutStr, int len, const char* pResponse, char delimeter)
648 {
649  //LOGF_DEBUG("GetParamStr('%s', '%s', '%c')", pInStr, pResponse, (delimeter == 0 ? '0' : delimeter));
650 
651  if((pResponse != NULL) && (*pResponse == 0))
652  pResponse = NULL;
653 
654  if(pResponse)
655  {
656  const char* pFind = strstr(pInStr, pResponse);
657  if(pFind == 0)
658  {
659  LOG_ERROR("Fail!");
660  return false;
661  }
662  int l = strlen(pResponse);
663  pInStr = pFind + l;
664  len -= l;
665  }
666 
667  if(len <= 0)
668  return false;
669 
670  for(int i = 0; i < 3; i++)
671  {
672  if(*pInStr == ' ')
673  {
674  pInStr++;
675  len--;
676 
677  if(len <= 0)
678  return false;
679  }
680  else
681  break;
682  }
683 
684  strncpy(pOutStr, pInStr, len);
685 
686  if(delimeter)
687  {
688  char* pDel = strchr(pOutStr, delimeter);
689  if(pDel == 0)
690  {
691  LOG_ERROR("Fail!");
692  return false;
693  }
694 
695  *pDel = 0;
696  }
697 
698  LOG_DEBUG(pOutStr);
699 
700  return true;
701 }
702 
703 bool TitanTCS::GetParamNumber(const char* pInStr, char* pOutStr, int len, const char* pResponse, char delimeter,
704  double *pDouble, int *pInteger)
705 {
706  if(!GetParamStr(pInStr, pOutStr, len, pResponse, delimeter))
707  return false;
708 
709  if(pDouble)
710  *pDouble = atof(pOutStr);
711  if(pInteger)
712  *pInteger = atoi(pOutStr);
713 
714  return true;
715 }
716 
717 bool TitanTCS::GetParamHour(const char* pInStr, char* pOutStr, int len, const char* pResponse, char delimeter,
718  double *pHour)
719 {
720  if(!GetParamStr(pInStr, pOutStr, len, pResponse, delimeter))
721  return false;
722 
723  //LOGF_DEBUG("pResult = '%s'", pOutStr);
724  if(HMS2Hour(pOutStr, pHour))
725  return true;
726 
727  return false;
728 }
729 
730 // -----------------------------------------------------------------------------
731 bool TitanTCS::SendCommand(const char *cmd)
732 {
733  if (isSimulation())
734  return false;
735 
736  // tcflush(PortFD, TCIOFLUSH); // Error with Bluetooth!
737  ReadFlush();
738 
739  int nbytes_written = 0;
740  int err_code;
741 
742  if ((err_code = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written) != TTY_OK))
743  {
744  char titanfocus_error[256];
745  tty_error_msg(err_code, titanfocus_error, 256);
746  LOGF_ERROR("tty_write() error detected: %s", titanfocus_error);
747  return false;
748  }
749 
750  // tcflush(PortFD, TCIOFLUSH); // Error with Bluetooth!
751 
752  return true;
753 }
754 
755 bool TitanTCS::SendCommand(const char *cmd, int val)
756 {
757  char szBuff[128];
758  sprintf(szBuff, cmd, val);
759 
760  return SendCommand(szBuff);
761 }
762 
763 bool TitanTCS::SendCommand(const char *cmd, double val)
764 {
765  char szBuff[128];
766  sprintf(szBuff, cmd, val);
767 
768  return SendCommand(szBuff);
769 }
770 // -----------------------------------------------------------------------------
771 void TitanTCS::ReadFlush()
772 {
773  if (isSimulation())
774  return;
775 
776  char buff[256];
777  int bytesRead = 0;
778 
779  // tcflush(PortFD, TCIOFLUSH); // Error with Bluetooth!
780 
781  for(int i = 0; i < 3; i++)
782  {
783  int err_code;
784  if ((err_code = tty_read(PortFD, buff, sizeof(buff) - 1, 0, &bytesRead)) != TTY_OK)
785  {
786  return;
787  }
788  if(bytesRead <= 0)
789  return;
790 
791  buff[bytesRead] = 0;
792  LOGF_DEBUG("Buffer Flush '%s'", buff);
793  }
794 }
795 
796 int TitanTCS::ReadResponse(char *buf, int len, char delimeter, int timeout)
797 {
798  if (isSimulation())
799  return 0;
800 
801  *buf = 0;
802  int bytesRead = 0;
803  int recv_len = 0;
804 
805  // tcflush(PortFD, TCIOFLUSH); // Error with Bluetooth!
806 
807  for(int i = 0; i < len; i++)
808  {
809  int err_code = tty_read(PortFD, buf + recv_len, 1, timeout, &bytesRead);
810  if (err_code != TTY_OK)
811  {
812  //if(err_code == TTY_TIME_OUT)
813  // continue;
814 
815  char titanfocus_error[256] = {0};
816  tty_error_msg(err_code, titanfocus_error, 256);
817  LOGF_ERROR("tty_read() error detected: '%s' len %d, %s", buf, recv_len, titanfocus_error);
818  return -1;
819  }
820 
821  char read_ch = buf[recv_len];
822  recv_len++;
823  buf[recv_len] = 0;
824 
825  if(delimeter == 0)
826  {
827  if(recv_len >= len)
828  {
829  return recv_len;
830  }
831  }
832  else
833  {
834  if((recv_len + 1) >= len)
835  {
836  LOGF_ERROR("TTY error detected: overflow %d, %d", recv_len, len);
837  return 0;
838  }
839  }
840 
841  if(delimeter)
842  {
843  if(read_ch == delimeter)
844  {
845  return recv_len;
846  }
847  }
848  }
849 
850  return -1;
851 }
852 // -----------------------------------------------------------------------------
853 bool TitanTCS::CommandResponse(const char* pCommand, const char* pResponse, char delimeter, double *pDouble, int *pInteger)
854 {
855  ReadFlush();
856  if (!SendCommand(pCommand))
857  return false;
858 
859  char szResponse[MAX_CMD_LEN] = { 0 };
860  char szResult[MAX_CMD_LEN] = { 0 };
861 
862  int rd_count = ReadResponse(szResponse, sizeof(szResponse), delimeter);
863  if (rd_count <= 0)
864  {
865  LOGF_ERROR("No response '%s'", pCommand);
866  return false;
867  }
868  LOGF_DEBUG("ReadResponse('%s')", szResponse);
869 
870  if(!GetParamNumber(szResponse, szResult, sizeof(szResult) - 1, pResponse, delimeter, pDouble, pInteger))
871  {
872  LOGF_DEBUG("CommandResponse('%s', '%s') Fail!", pCommand, pResponse);
873  return false;
874  }
875 
876  return true;
877 }
878 
879 bool TitanTCS::CommandResponseHour(const char* pCommand, const char* pResponse, char delimeter, double* Hour)
880 {
881  ReadFlush();
882  if (!SendCommand(pCommand))
883  return false;
884 
885  char szResponse[MAX_CMD_LEN] = { 0 };
886  char szResult[MAX_CMD_LEN] = { 0 };
887 
888  int rd_count = ReadResponse(szResponse, sizeof(szResponse), delimeter);
889  if (rd_count <= 0)
890  {
891  LOGF_ERROR("No response '%s'", pCommand);
892  return false;
893  }
894  LOGF_DEBUG("ReadResponse('%s')", szResponse);
895 
896  if(!GetParamHour(szResponse, szResult, sizeof(szResult) - 1, pResponse, delimeter, Hour))
897  {
898  LOGF_DEBUG("CommandResponseHour('%s', '%s') Fail!", pCommand, pResponse);
899  return false;
900  }
901 
902  return true;
903 }
904 
905 bool TitanTCS::CommandResponseStr(const char* pCommand, const char* pResponse, char delimeter, char* pReturn, int len)
906 {
907  ReadFlush();
908  if (!SendCommand(pCommand))
909  return false;
910 
911  char szResponse[MAX_CMD_LEN * 2] = { 0 };
912 
913  int rd_count = ReadResponse(szResponse, sizeof(szResponse), delimeter);
914  if (rd_count <= 0)
915  {
916  LOGF_ERROR("No response '%s'", pCommand);
917  return false;
918  }
919  LOGF_DEBUG("ReadResponse('%s')", szResponse);
920 
921  if(!GetParamStr(szResponse, pReturn, len, pResponse, delimeter))
922  {
923  LOGF_DEBUG("CommandResponseStr('%s', '%s') Fail!", pCommand, pResponse);
924  return false;
925  }
926 
927  LOGF_DEBUG("%s : %s", pCommand, pReturn);
928 
929  return true;
930 }
931 
932 bool TitanTCS::CommandResponseChar(const char* pCommand, const char* pResponse, char* pReturn)
933 {
934  ReadFlush();
935  if (!SendCommand(pCommand))
936  return false;
937 
938  char szResponse[MAX_CMD_LEN] = { 0 };
939  char szResult[MAX_CMD_LEN] = { 0 };
940 
941  int rd_count = ReadResponse(szResponse, 1, 0);
942  if (rd_count <= 0)
943  {
944  LOGF_ERROR("No response '%s'", pCommand);
945  return false;
946  }
947  //LOGF_DEBUG("ReadResponse('%s')", szResponse);
948 
949  if(!GetParamStr(szResponse, szResult, sizeof(szResult) - 1, pResponse, 0))
950  {
951  LOGF_DEBUG("CommandResponseChar('%s', '%s') Fail!", pCommand, pResponse);
952  return false;
953  }
954 
955  *pReturn = szResult[0];
956 
957  LOGF_DEBUG("%s : %c", pCommand, *pReturn);
958 
959  return true;
960 }
961 
962 bool TitanTCS::SetTarget(double ra, double dec)
963 {
964  char szRA[MAX_CMD_LEN], szDEC[MAX_CMD_LEN];
965  formatRA(ra * 3600, szRA);
966  formatDEC(dec * 3600, szDEC);
967 
968  char rtnCode = 0;
969  char szCommand[MAX_CMD_LEN * 2];
970 
971  sprintf(szCommand, "#:Sr %s#", szRA);
972  if(!CommandResponseChar(szCommand, "", &rtnCode))
973  {
974  LOG_ERROR("SetTarget RA / No response");
975  return false;
976  }
977  if(rtnCode != '1')
978  {
979  LOGF_ERROR("SetTarget DEC / Error Code = '%c'", rtnCode);
980  return false;
981  }
982 
983  sprintf(szCommand, "#:Sd %s#", szDEC);
984  if(!CommandResponseChar(szCommand, "", &rtnCode))
985  {
986  LOG_ERROR("SetTarget DEC / No response");
987  return false;
988  }
989  if(rtnCode != '1')
990  {
991  LOGF_ERROR("SetTarget DEC / Error Code = '%c'", rtnCode);
992  return false;
993  }
994 
995  LOGF_INFO("Set target RA:%s, DEC:%s", szRA, szDEC);
996  return true;
997 }
998 
999 void TitanTCS::guideTimeoutNS()
1000 {
1001  GuideNSNP.np[0].value = 0;
1002  GuideNSNP.np[1].value = 0;
1003  GuideNSNP.s = IPS_IDLE;
1004  GuideNSTID = 0;
1005  IDSetNumber(&GuideNSNP, nullptr);
1006 }
1007 
1008 void TitanTCS::guideTimeoutWE()
1009 {
1010  GuideWENP.np[0].value = 0;
1011  GuideWENP.np[1].value = 0;
1012  GuideWENP.s = IPS_IDLE;
1013  GuideWETID = 0;
1014  IDSetNumber(&GuideWENP, nullptr);
1015 }
1016 
1017 void TitanTCS::guideTimeoutHelperNS(void * p)
1018 {
1019  static_cast<TitanTCS *>(p)->guideTimeoutNS();
1020 }
1021 
1022 void TitanTCS::guideTimeoutHelperWE(void * p)
1023 {
1024  static_cast<TitanTCS *>(p)->guideTimeoutWE();
1025 }
1026 
1027 bool TitanTCS::GetMountParams(bool bAll)
1028 {
1029  INDI_UNUSED(bAll);
1030 
1031  static int cnt = 0;
1032 
1033  char szCommand[256];
1034  sprintf(szCommand, "#:\\GE($GR #:GR#"
1035  ":\\GE$GD #:GD#"
1036  "#:hP?#"
1037  ":\\?pe#"
1038  ":\\?tm#"
1039  ":\\?tr#"
1040  ":\\?ts#"
1041  ":\\GE%d)#", cnt++);
1042 
1043  //strcpy(szCommand, "#:hP?#" ":\\GE}#");
1044 
1045  char szResponse[256];
1046  if(!CommandResponseStr(szCommand, "(", ')', szResponse, sizeof(szResponse) - 1))
1047  return false;
1048 
1049  char szToken[128];
1050  // RA & DEC Coordinate
1051  if(GetParamHour(szResponse, szToken, sizeof(szToken) - 1, "$GR", '#', &info.ra))
1052  {
1053  if(GetParamHour(szResponse, szToken, sizeof(szToken) - 1, "$GD", '#', &info.dec))
1054  {
1055  LOGF_DEBUG("RA %g, DEC %g", info.ra, info.dec);
1056  NewRaDec(info.ra, info.dec);
1057  }
1058  }
1059 
1060 #if USE_PEC
1061  // PEC Status
1062  if(GetParamNumber(szResponse, szToken, sizeof(szToken) - 1, "$?pe", '#', NULL, &info.PECStatus))
1063  {
1064  LOGF_DEBUG("PEC Status %d", info.PECStatus);
1065  _setPECState(info.PECStatus);
1066  }
1067 #endif
1068 
1069  // Slewing Status bit0:RA Tracking, bit1:DEC Tracking, bit2:RA Slewing, bit3:DEC Slewing, bit4,5:Goto status
1070  if(GetParamNumber(szResponse, szToken, sizeof(szToken) - 1, "$?ts", '#', NULL, &info.TrackingStatus))
1071  {
1072  LOGF_DEBUG("Tracking Status %d", info.TrackingStatus);
1073 
1074  if(info.TrackingStatus & 0x3C)
1075  {
1077  }
1078  else if(info.TrackingStatus == 3)
1079  {
1081  }
1082  else
1083  {
1085  }
1086  }
1087  // Parking Status
1088  if(GetParamNumber(szResponse, szToken, sizeof(szToken) - 1, "$hP", '#', NULL, &info.Parking))
1089  {
1090  LOGF_DEBUG("Parking Status %d", info.Parking);
1091 
1092  if(info.Parking == 1)
1093  {
1095  ParkS[0].s = ISS_ON;
1096  ParkS[1].s = ISS_OFF;
1097  ParkSP.s = IPS_BUSY;
1098  IUSaveText(&MountInfoT[0], "Parking");
1099  }
1100  else if(info.Parking == 2)
1101  {
1103  ParkS[0].s = ISS_ON;
1104  ParkS[1].s = ISS_OFF;
1105  ParkSP.s = IPS_IDLE;
1106  IUSaveText(&MountInfoT[0], "Parked");
1107  }
1108  else if(info.Parking == 0)
1109  {
1110  ParkSP.s = IPS_IDLE;
1111  ParkS[0].s = ISS_OFF;
1112  ParkS[1].s = ISS_ON;
1113  IUSaveText(&MountInfoT[0], "Unpark");
1114  }
1115 
1116  IDSetSwitch(&ParkSP, nullptr);
1117  }
1118  // Tracking On / Off
1120  {
1124  IDSetSwitch(&TrackStateSP, nullptr);
1125 
1126  if(TrackState == SCOPE_PARKING)
1127  IUSaveText(&MountInfoT[1], "Parking");
1128  else if(TrackState == SCOPE_PARKED)
1129  IUSaveText(&MountInfoT[1], "Parked");
1130  else if(TrackState == SCOPE_SLEWING)
1131  IUSaveText(&MountInfoT[1], "Slewing");
1132  }
1133  else
1134  {
1135  if(GetParamNumber(szResponse, szToken, sizeof(szToken) - 1, "$?tm", '#', NULL, &info.Landscape))
1136  {
1137  LOGF_DEBUG("? %d, %d", TrackState, info.Landscape);
1138 
1139  if((TrackState == SCOPE_TRACKING) && (info.Landscape == 0))
1140  {
1144  IDSetSwitch(&TrackStateSP, nullptr);
1145 
1146  IUSaveText(&MountInfoT[1], "Tracking ON / Skyview");
1147  }
1148  else
1149  {
1153  IDSetSwitch(&TrackStateSP, nullptr);
1154 
1155  if(info.Landscape == 1)
1156  IUSaveText(&MountInfoT[1], "Tracking OFF / Landscape");
1157  else
1158  IUSaveText(&MountInfoT[1], "Tracking OFF / Idle");
1159  }
1160  }
1161  }
1162  //
1163  MountInfoTP.s = IPS_OK;
1164  IDSetText(&MountInfoTP, nullptr);
1165  //
1166  if(GetParamNumber(szResponse, szToken, sizeof(szToken) - 1, "$?tr", '#', NULL, &info.TrackingRate))
1167  {
1168  LOGF_DEBUG("Tracking rate %d", info.TrackingRate);
1169 
1170  TrackModeS[0].s = info.TrackingRate == 0 ? ISS_ON : ISS_OFF;
1171  TrackModeS[1].s = info.TrackingRate == 1 ? ISS_ON : ISS_OFF;
1172  TrackModeS[2].s = info.TrackingRate == 2 ? ISS_ON : ISS_OFF;
1173  IDSetSwitch(&TrackModeSP, nullptr);
1174  }
1175  //
1176  static int prev_TrackState = -1;
1177  if(prev_TrackState != TrackState)
1178  {
1179  prev_TrackState = TrackState;
1180 
1181  switch(TrackState)
1182  {
1183  case SCOPE_IDLE:
1184  LOG_INFO("Track State : IDLE");
1185  break;
1186  case SCOPE_SLEWING:
1187  LOG_INFO("Track State : SLEWING");
1188  break;
1189  case SCOPE_TRACKING:
1190  LOG_INFO("Track State : TRACKING");
1191  break;
1192  case SCOPE_PARKING:
1193  LOG_INFO("Track State : PARKING");
1194  break;
1195  case SCOPE_PARKED:
1196  LOG_INFO("Track State : PARKED");
1197  break;
1198  }
1199  }
1200 
1201  return true;
1202 }
1203 #if USE_PEC
1204 void TitanTCS::_setPECState(int pec_status)
1205 {
1206  if (_PECStatus != pec_status)
1207  {
1208  //LOGF_INFO("_setPECState(%x)", pec_status);
1209  char szText[128];
1210 
1211  _PECStatus = pec_status;
1212  // PEC Enabled BIT 0
1213  // PEC Valid BIT 1
1214  // PEC Training BIT 2
1215  // PEC Stopping BIT 3
1216 
1217  if(pec_status & 0x30)
1218  {
1219  // Training ...
1220  PECTrainingS[0].s = ISS_OFF;
1221  PECTrainingS[1].s = ISS_ON;
1222 
1223  sprintf(szText, "PEC Training %d %%", (pec_status >> 8));
1224  IUSaveText(&PECInfoT[1], szText);
1225  }
1226  else
1227  {
1228  PECTrainingS[0].s = ISS_ON;
1229  PECTrainingS[1].s = ISS_OFF;
1230 
1231  IUSaveText(&PECInfoT[1], "");
1232  }
1233 
1234  if(pec_status & 2)
1235  {
1236  // Valid
1237  if(pec_status & 1)
1238  {
1239  PECStateS[PEC_OFF].s = ISS_OFF;
1240  PECStateS[PEC_ON].s = ISS_ON;
1241 
1242  IUSaveText(&PECInfoT[0], "PEC is running.");
1243  }
1244  else
1245  {
1246  PECStateS[PEC_OFF].s = ISS_OFF;
1247  PECStateS[PEC_ON].s = ISS_ON;
1248 
1249  IUSaveText(&PECInfoT[0], "PEC is available.");
1250  }
1251  PECStateSP.s = IPS_OK;
1252  }
1253  else
1254  {
1255  // Invalid
1256  PECStateS[PEC_OFF].s = ISS_OFF;
1257  PECStateS[PEC_ON].s = ISS_OFF;
1259 
1260  if(pec_status & 0x30)
1261  IUSaveText(&PECInfoT[0], "");
1262  else
1263  IUSaveText(&PECInfoT[0], "PEC training is required.");
1264  }
1265 
1266  PECStateSP.s = IPS_OK;
1267  IDSetSwitch(&PECStateSP, nullptr);
1268 
1269  PECTrainingSP.s = IPS_OK;
1270  IDSetSwitch(&PECTrainingSP, nullptr);
1271  //
1272  PECInfoTP.s = IPS_OK;
1273  IDSetText(&PECInfoTP, nullptr);
1274  }
1275 }
1276 #endif
1277 
1278 // -----------------------------------------------------------------------------
1279 bool TitanTCS::updateTime(ln_date *utc, double utc_offset)
1280 {
1281  ln_zonedate ltm;
1282 
1283  if (isSimulation())
1284  return true;
1285 
1286  double JD = ln_get_julian_day(utc);
1287 
1288  LOGF_DEBUG("New JD is %.2f", JD);
1289 
1290  ln_date_to_zonedate(utc, &ltm, utc_offset * 3600);
1291 
1292  LOGF_DEBUG("Local time is %02d:%02d:%02g", ltm.hours, ltm.minutes, ltm.seconds);
1293 
1294  char szText[128];
1295  sprintf(szText, "#:SG %.1f#:SC %02d/%02d/%02d#:SL %02d:%02d:%02d#",
1296  -utc_offset,
1297  ltm.months, ltm.days, ltm.years % 100,
1298  ltm.hours, ltm.minutes, (int)ltm.seconds % 60);
1299 
1300  LOGF_INFO("Set datetime '%s'", szText);
1301 
1302  return SendCommand(szText);
1303 }
1304 
1305 // -----------------------------------------------------------------------------
1306 bool TitanTCS::updateLocation(double latitude, double longitude, double elevation)
1307 {
1308  INDI_UNUSED(elevation);
1309 
1310  if((fabs(latitude) < 0.001) && (fabs(longitude) < 0.001))
1311  return false;
1312 
1313  int d = 0, m = 0, s = 0;
1314  char szCommand[128];
1315  char rtnCode = 0;
1316 
1317  getSexComponents(latitude, &d, &m, &s);
1318  sprintf(szCommand, "#:St %03d:%02d:%02d#", d, m, s);
1319  LOGF_INFO("Set latitude '%s'", szCommand);
1320  if(!CommandResponseChar(szCommand, NULL, &rtnCode))
1321  return false;
1322 
1323  getSexComponents(-longitude, &d, &m, &s);
1324  sprintf(szCommand, "#:Sg %03d:%02d:%02d#", d, m, s);
1325  LOGF_INFO("Set longitude '%s'", szCommand);
1326  return CommandResponseChar(szCommand, NULL, &rtnCode);
1327 }
1328 
1329 bool TitanTCS::Sync(double ra, double dec)
1330 {
1331  if(!SetTarget(ra, dec))
1332  return false;
1333 
1334  char rtnCode[64] = { "" };
1335  char szCommand[MAX_CMD_LEN];
1336  sprintf(szCommand, ":CM#");
1337 
1338  if(!CommandResponseStr(szCommand, "", '#', rtnCode, sizeof(rtnCode) - 1))
1339  {
1340  LOG_ERROR("Sync / No response");
1341  return false;
1342  }
1343  if(strcmp(rtnCode, "1") != 0)
1344  {
1345  LOGF_ERROR("Sync / Error Code = '%s'", rtnCode);
1346  return false;
1347  }
1348 
1349  LOG_INFO("Sync");
1350  return true;
1351 }
1352 // -----------------------------------------------------------------------------
1354 {
1355  char chDir = 0;
1356 
1357  switch(dir)
1358  {
1359  case DIRECTION_NORTH:
1360  chDir = 'n';
1361  break;
1362  case DIRECTION_SOUTH:
1363  chDir = 's';
1364  break;
1365  default:
1366  return false;
1367  break;
1368  }
1369 
1370  char szCommand[MAX_CMD_LEN];
1371  if(command == MOTION_START)
1372  {
1373  sprintf(szCommand, ":M%c#", chDir);
1374  }
1375  else
1376  {
1377  sprintf(szCommand, ":Q%c#", chDir);
1378  }
1379 
1380  //TrackState = SCOPE_SLEWING;
1381  LOGF_INFO("Moving command:%s", szCommand);
1382  return SendCommand(szCommand);
1383 }
1384 
1385 // -----------------------------------------------------------------------------
1387 {
1388  char chDir = 0;
1389 
1390  switch(dir)
1391  {
1392  case DIRECTION_EAST:
1393  chDir = 'e';
1394  break;
1395  case DIRECTION_WEST:
1396  chDir = 'w';
1397  break;
1398  default:
1399  return false;
1400  break;
1401  }
1402 
1403  char szCommand[MAX_CMD_LEN];
1404  if(command == MOTION_START)
1405  {
1406  sprintf(szCommand, ":M%c#", chDir);
1407  }
1408  else
1409  {
1410  sprintf(szCommand, ":Q%c#", chDir);
1411  }
1412 
1413  //TrackState = SCOPE_SLEWING;
1414  LOGF_INFO("Moving command:%s", szCommand);
1415  return SendCommand(szCommand);
1416 }
1417 // -----------------------------------------------------------------------------
1419 {
1420  LOG_INFO("Parking ...");
1421 
1422  if(SendCommand(":hP8#"))
1423  {
1424  ParkSP.s = IPS_BUSY;
1426  return true;
1427  }
1428  return false;
1429 }
1430 // -----------------------------------------------------------------------------
1432 {
1433  LOG_INFO("Unparking ...");
1434 
1435  if(SendCommand(":hP0#"))
1436  {
1437  ParkSP.s = IPS_BUSY;
1439  return true;
1440  }
1441  return false;
1442 }
1443 
1444 // -----------------------------------------------------------------------------
1445 bool TitanTCS::SetTrackMode(uint8_t mode)
1446 {
1447  LOGF_INFO("SetTrackMode(%d)", mode);
1448  return SendCommand("#:\\T%d#", mode);
1449 }
1450 // -----------------------------------------------------------------------------
1451 /*
1452 T.B.D
1453 bool TitanTCS::SetTrackRate(double raRate, double deRate)
1454 {
1455  return true;
1456 }
1457 */
1458 // -----------------------------------------------------------------------------
1459 bool TitanTCS::SetTrackEnabled(bool enabled)
1460 {
1461  if(enabled)
1462  {
1463  LOG_INFO("Tracking ON");
1464  return SendCommand("#:\\t0#"); // Tracking
1465  }
1466  else
1467  {
1468  LOG_INFO("Tracking OFF");
1469  return SendCommand("#:\\t1#"); // Stop
1470  }
1471 }
1472 
1473 // -----------------------------------------------------------------------------
1474 bool TitanTCS::SetParkPosition(double Axis1Value, double Axis2Value)
1475 {
1476  INDI_UNUSED(Axis1Value);
1477  INDI_UNUSED(Axis2Value);
1478 
1479  return true;
1480 }
1481 
1483 {
1484  return true;
1485 }
1486 // -----------------------------------------------------------------------------
1488 {
1489  return true;
1490 }
1491 
1492 bool TitanTCS::SetSlewRate(int index)
1493 {
1494  LOGF_INFO("Set Slew Rate '%d'", index);
1495 
1496  switch (index)
1497  {
1498  case 3:
1499  return SendCommand(":RS#");
1500  case 2:
1501  return SendCommand(":RM#");
1502  case 1:
1503  return SendCommand(":RC#");
1504  case 0:
1505  return SendCommand(":RG#");
1506  }
1507  return false;
1508 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
ISwitchVectorProperty ParkSP
ISwitch PECStateS[2]
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
ISwitch * TrackModeS
ISwitch ParkS[2]
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.
ISwitch TrackStateS[2]
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-.
Definition: crux_mount.cpp:534
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: crux_mount.cpp:637
virtual bool Disconnect() override
Disconnect from device.
Definition: crux_mount.cpp:79
virtual bool Park() override
Park the telescope to its home position.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
Definition: crux_mount.cpp:625
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
Definition: crux_mount.cpp:317
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: crux_mount.cpp:200
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
Definition: crux_mount.cpp:309
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-.
Definition: crux_mount.cpp:568
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.
Definition: crux_mount.cpp:135
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
Definition: crux_mount.cpp:551
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: crux_mount.cpp:171
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...
Definition: crux_mount.cpp:64
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+.
Definition: crux_mount.cpp:517
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: crux_mount.cpp:92
virtual const char * getDefaultName() override
Definition: crux_mount.cpp:588
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.
Definition: crux_mount.cpp:596
#define HANDSHAKE_NAME
Definition: crux_mount.cpp:31
#define MAX_CMD_LEN
Definition: crux_mount.cpp:33
#define PRODUCT_NAME
Definition: crux_mount.cpp:30
#define MIN_FW_VERSION
Definition: crux_mount.cpp:32
#define USE_PEC
Definition: crux_mount.h:27
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().
Definition: eventloop.c:602
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.
Definition: eventloop.c:582
double ra
double dec
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
INDI_DIR_WE
Definition: indibasetypes.h:55
@ DIRECTION_EAST
Definition: indibasetypes.h:57
@ DIRECTION_WEST
Definition: indibasetypes.h:56
INDI_DIR_NS
Definition: indibasetypes.h:48
@ DIRECTION_SOUTH
Definition: indibasetypes.h:50
@ DIRECTION_NORTH
Definition: indibasetypes.h:49
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:254
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
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.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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.
Definition: indidevapi.c:158
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.
Definition: indidevapi.c:198
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.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250
int Landscape
Definition: crux_mount.h:38
int TrackingRate
Definition: crux_mount.h:39
int TrackingStatus
Definition: crux_mount.h:40
double dec
Definition: crux_mount.h:32
double ra
Definition: crux_mount.h:31
int Parking
Definition: crux_mount.h:34
int PECStatus
Definition: crux_mount.h:36