Instrument Neutral Distributed Interface INDI  2.0.2
ioptronHC8406.cpp
Go to the documentation of this file.
1 /*
2  ioptronHC8406 INDI driver
3 
4  Copyright (C) 2017 Nacho Mas. Base on GotoNova driver by Jasem Mutlaq
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 /*
22 HC8406 CMD hardware TEST
23 V1.10 March 21, 2011
24 UPGRADE INFO ON: http://www.ioptron.com/Articles.asp?ID=268
25 
26 INFO
27 ----
28 # -> repeat last command
29 :GG# +08:00:00 UTC OffSet
30 :Gg# -003*18:03# longitud
31 :Gt# +41*06:56# latitude
32 :GL# 7:02:47.0# local time
33 :GS# 20:12: 3.3# Sideral Time
34 :GR# 2:12:57.4# RA
35 :GD# +90* 0: 0# DEC
36 :GA# +41* 6:55# ALT
37 :GZ# 0* 0: 0# AZ
38 :GC# 03:12:09# Calendar day
39 :pS# East# pier side
40 :FirmWareDate# :20110506#
41 :V# V1.00#
42 
43 COMMANDS
44 --------
45 :CM# Coordinates matched. #
46 :CMR# Coordinates matched. #
47 
48 This only works if the mount is not stopped (tracking)
49 :RT0# --> Lunar
50 :RT1# --> solar
51 :RT2# --> sideral
52 :RT9# --> zero but not work!!
53 
54 !!!There isn't a command to start/stop tracking !!! You have to do manualy
55 
56 This speeds only are taken into account for protocol buttons, not for the HC Buttons
57 :RG# --> Select guide speed for :Mn#,:Ms# ....
58 :RG0,1,2 -->preselect guide speed 0.25x, 0.5x, 1.0x (HC shows it)
59 :RC# --> Select center speed for :Mn#,:Ms# .... (Not Works)
60 :RC0,1,2 -->preselect guide speed (HC doesn't shows it)
61 :Mn# :Ms# :Me# :Mw# (move until :Q# at guiding or center speed :RG# (works)or :RC#(not work, use :RC0/1/2 instead))
62 :MnXXX# :MsXXX# :MeXXX# :MwXXX# (move XXX ms at guiding speed no mather what :RCx#,:RGX# or :RSX# was issue)
63 
64 Firmware update (HC v1.10 -> v1.12, also mainboard firmware)
65 ------------------------------------------------------------------
66 HC8406 CMD hardware TEST
67 V1.12 2011-08-12
68 UPGRADE INFO ON: http://www.ioptron.com/Articles.asp?ID=268
69 
70 :RT9# -> stop tracking
71 :RT0# -> start tracking at sidera speed. Formerly only preselect sideral speed but
72  not start the tracking itself
73 
74 :Me#
75 :Mw#
76 :Mexxx#
77 :Mwxxx# ->Al this commands are broken. Only RA axes, the equivalent :Ms#,:Mn#... work.
78 
79 Summarizing:
80 
81 old firmware v1.10: is not possible to start/stop tracking. Guide/move commands OK
82 new firmware v1.12: is possible to start/stop tracking. Guide/move commands NOT OK
83 
84 */
85 
86 /* SOCAT sniffer
87 socat -v PTY,link=/tmp/serial,wait-slave,raw /dev/ttyUSB0,raw
88 */
89 
90 
91 
92 #include "ioptronHC8406.h"
93 
94 #include "indicom.h"
95 #include "lx200driver.h"
96 
97 #include <libnova/transform.h>
98 
99 #include <cmath>
100 #include <cstring>
101 #include <termios.h>
102 #include <unistd.h>
103 
104 /* Simulation Parameters */
105 #define SLEWRATE 1 /* slew rate, degrees/s */
106 #define SIDRATE 0.004178 /* sidereal rate, degrees/s */
107 #define ioptronHC8406_TIMEOUT 1 /* timeout */
108 #define ioptronHC8406_CALDATE_RESULT " # " /* result of calendar date */
109 
110 
112 {
113  setVersion(1, 3);
118 
119 }
120 
122 {
124 
125  // Sync Type
126  IUFillSwitch(&SyncCMRS[USE_REGULAR_SYNC], "USE_REGULAR_SYNC", ":CM#", ISS_ON);
127  IUFillSwitch(&SyncCMRS[USE_CMR_SYNC], "USE_CMR_SYNC", ":CMR#", ISS_OFF);
128  IUFillSwitchVector(&SyncCMRSP, SyncCMRS, 2, getDeviceName(), "SYNC_MODE", "Sync", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0,
129  IPS_IDLE);
130 
131  // Cursor move Guiding/Center
132  IUFillSwitch(&CursorMoveSpeedS[USE_GUIDE_SPEED], "USE_GUIDE_SPEED", "Guide Speed", ISS_ON);
133  IUFillSwitch(&CursorMoveSpeedS[USE_CENTERING_SPEED], "USE_CENTERING_SPEED", "Centering Speed", ISS_OFF);
134  IUFillSwitchVector(&CursorMoveSpeedSP, CursorMoveSpeedS, 2, getDeviceName(),
135  "CURSOR_MOVE_MODE", "Cursor Move Speed", MOTION_TAB, IP_RO, ISR_1OFMANY, 0, IPS_IDLE);
136 
137  // Guide Rate
138  IUFillSwitch(&GuideRateS[0], "0.25x", "", ISS_OFF);
139  IUFillSwitch(&GuideRateS[1], "0.50x", "", ISS_ON);
140  IUFillSwitch(&GuideRateS[2], "1.0x", "", ISS_OFF);
141  IUFillSwitchVector(&GuideRateSP, GuideRateS, 3, getDeviceName(),
142  "GUIDE_RATE", "Guide Speed", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
143 
144  // Center Rate
145  IUFillSwitch(&CenterRateS[0], "12x", "", ISS_OFF);
146  IUFillSwitch(&CenterRateS[1], "64x", "", ISS_ON);
147  IUFillSwitch(&CenterRateS[2], "600x", "", ISS_OFF);
148  IUFillSwitch(&CenterRateS[3], "1200x", "", ISS_OFF);
149  IUFillSwitchVector(&CenterRateSP, CenterRateS, 4, getDeviceName(),
150  "CENTER_RATE", "Center Speed", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
151 
152  TrackModeSP.nsp = 3;
153 
154  return true;
155 }
156 
158 {
160 
161  if (isConnected())
162  {
163  defineProperty(&SyncCMRSP);
164  defineProperty(&GuideRateSP);
165  defineProperty(&CenterRateSP);
166  defineProperty(&CursorMoveSpeedSP);
167  ioptronHC8406Init();
168  }
169  else
170  {
171  deleteProperty(SyncCMRSP.name);
172  deleteProperty(GuideRateSP.name);
173  deleteProperty(CenterRateSP.name);
174  deleteProperty(CursorMoveSpeedSP.name);
175  }
176 
177  return true;
178 }
179 
181 {
182  return (const char *)"iOptron HC8406";
183 }
184 
186 {
187  const timespec timeout = {0, 50000000L};
188 
189  if (isSimulation())
190  return true;
191 
192  char initCMD[] = ":V#";
193  int errcode = 0;
194  char errmsg[MAXRBUF];
195  char response[8];
196  int nbytes_read = 0;
197  int nbytes_written = 0;
198 
199  LOG_DEBUG("Initializing iOptron using :V# CMD...");
200 
201  for (int i = 0; i < 2; i++)
202  {
203  if ((errcode = tty_write(PortFD, initCMD, 3, &nbytes_written)) != TTY_OK)
204  {
205  tty_error_msg(errcode, errmsg, MAXRBUF);
206  LOGF_ERROR("%s", errmsg);
207  nanosleep(&timeout, nullptr);
208  continue;
209  }
210 
211  if ((errcode = tty_read_section(PortFD, response, '#', 3, &nbytes_read)))
212  {
213  tty_error_msg(errcode, errmsg, MAXRBUF);
214  LOGF_ERROR("%s", errmsg);
215  nanosleep(&timeout, nullptr);
216  continue;
217  }
218 
219  if (nbytes_read > 0)
220  {
221  response[nbytes_read] = '\0';
222  LOGF_DEBUG("RES (%s)", response);
223 
224  if (!strcmp(response, "V1.00#"))
225  return true;
226  }
227 
228  nanosleep(&timeout, nullptr);
229  }
230 
231  return false;
232 }
233 
234 bool ioptronHC8406::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
235 {
236  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
237  {
238 
239  // Sync type
240  if (!strcmp(name, SyncCMRSP.name))
241  {
242  IUResetSwitch(&SyncCMRSP);
243  IUUpdateSwitch(&SyncCMRSP, states, names, n);
244  IUFindOnSwitchIndex(&SyncCMRSP);
245  SyncCMRSP.s = IPS_OK;
246  IDSetSwitch(&SyncCMRSP, nullptr);
247  return true;
248  }
249 
250  // Cursor move type
251  if (!strcmp(name, CursorMoveSpeedSP.name))
252  {
253  int currentSwitch = IUFindOnSwitchIndex(&CursorMoveSpeedSP);
254  IUUpdateSwitch(&CursorMoveSpeedSP, states, names, n);
255  if (setioptronHC8406CursorMoveSpeed(IUFindOnSwitchIndex(&CursorMoveSpeedSP)) == TTY_OK)
256  CursorMoveSpeedSP.s = IPS_OK;
257  else
258  {
259  IUResetSwitch(&CursorMoveSpeedSP);
260  CursorMoveSpeedS[currentSwitch].s = ISS_ON;
261  CursorMoveSpeedSP.s = IPS_ALERT;
262  }
263  return true;
264  }
265 
266  // Guide Rate
267  if (!strcmp(GuideRateSP.name, name))
268  {
269  int currentSwitch = IUFindOnSwitchIndex(&GuideRateSP);
270  IUUpdateSwitch(&GuideRateSP, states, names, n);
271  if (setioptronHC8406GuideRate(IUFindOnSwitchIndex(&GuideRateSP)) == TTY_OK)
272  {
273  GuideRateSP.s = IPS_OK;
274  //Shows guide speed selected
275  CursorMoveSpeedS[USE_GUIDE_SPEED].s = ISS_ON;
276  CursorMoveSpeedS[USE_CENTERING_SPEED].s = ISS_OFF;
277  CursorMoveSpeedSP.s = IPS_OK;
278  IDSetSwitch(&CursorMoveSpeedSP, nullptr);
279  }
280  else
281  {
282  IUResetSwitch(&GuideRateSP);
283  GuideRateS[currentSwitch].s = ISS_ON;
284  GuideRateSP.s = IPS_ALERT;
285  }
286 
287  IDSetSwitch(&GuideRateSP, nullptr);
288  return true;
289  }
290 
291  // Center Rate
292  if (!strcmp(CenterRateSP.name, name))
293  {
294  int currentSwitch = IUFindOnSwitchIndex(&CenterRateSP);
295  IUUpdateSwitch(&CenterRateSP, states, names, n);
296  if (setioptronHC8406CenterRate(IUFindOnSwitchIndex(&CenterRateSP)) == TTY_OK)
297  {
298  CenterRateSP.s = IPS_OK;
299  //Shows centering speed selected
300  CursorMoveSpeedS[USE_GUIDE_SPEED].s = ISS_OFF;
301  CursorMoveSpeedS[USE_CENTERING_SPEED].s = ISS_ON;
302  CursorMoveSpeedSP.s = IPS_OK;
303  IDSetSwitch(&CursorMoveSpeedSP, nullptr);
304  }
305  else
306  {
307  IUResetSwitch(&CenterRateSP);
308  CenterRateS[currentSwitch].s = ISS_ON;
309  CenterRateSP.s = IPS_ALERT;
310  }
311 
312  IDSetSwitch(&CenterRateSP, nullptr);
313  return true;
314  }
315 
316  // // Slew Rate
317  // if (!strcmp(SlewRateSP.name, name))
318  // {
319  // int currentSwitch = IUFindOnSwitchIndex(&SlewRateSP);
320  // IUUpdateSwitch(&SlewRateSP, states, names, n);
321  // if (setioptronHC8406SlewRate(IUFindOnSwitchIndex(&SlewRateSP)) == TTY_OK)
322  // SlewRateSP.s = IPS_OK;
323  // else
324  // {
325  // IUResetSwitch(&SlewRateSP);
326  // SlewRateS[currentSwitch].s = ISS_ON;
327  // SlewRateSP.s = IPS_ALERT;
328  // }
329 
330  // IDSetSwitch(&SlewRateSP, nullptr);
331  // return true;
332  // }
333 
334  }
335 
336  return LX200Generic::ISNewSwitch(dev, name, states, names, n);
337 }
338 
340 {
341  /* HC8406 doesn't have :SE# or :SE? command, thus we check if the slew is
342  completed comparing targetRA/DEC with actual RA/DEC */
343 
344  float tolerance = 1 / 3600.; // 5 arcsec
345 
346  if (fabs(currentRA - targetRA) <= tolerance && fabs(currentDEC - targetDEC) <= tolerance)
347  return true;
348 
349  return false;
350 }
351 
353 {
356  sendScopeTime();
357 }
358 
359 void ioptronHC8406::ioptronHC8406Init()
360 {
361  //This mount doesn't report anything so we send some CMD
362  //just to get syncronize with the GUI at start time
363  LOG_WARN("Sending init CMDs. Unpark, Stop tracking");
364  UnPark();
366  SetTrackEnabled(false);
367  setioptronHC8406GuideRate(1);
368 }
369 
370 bool ioptronHC8406::Goto(double r, double d)
371 {
372  const timespec timeout = {0, 100000000L};
373 
374  targetRA = r;
375  targetDEC = d;
376  char RAStr[64], DecStr[64];
377 
378  fs_sexa(RAStr, targetRA, 2, 3600);
379  fs_sexa(DecStr, targetDEC, 2, 3600);
380  LOGF_DEBUG("<GOTO RA/DEC> %s/%s", RAStr, DecStr);
381 
382  // If moving, let's stop it first.
383  if (EqNP.s == IPS_BUSY)
384  {
385  if (!isSimulation() && abortSlew(PortFD) < 0)
386  {
387  AbortSP.s = IPS_ALERT;
388  IDSetSwitch(&AbortSP, "Abort slew failed.");
389  return false;
390  }
391 
392  AbortSP.s = IPS_OK;
393  EqNP.s = IPS_IDLE;
394  IDSetSwitch(&AbortSP, "Slew aborted.");
395  IDSetNumber(&EqNP, nullptr);
396 
398  {
401  EqNP.s = IPS_IDLE;
404  IDSetSwitch(&MovementNSSP, nullptr);
405  IDSetSwitch(&MovementWESP, nullptr);
406  }
407 
408  // sleep for 100 mseconds
409  nanosleep(&timeout, nullptr);
410  }
411 
412  if (!isSimulation())
413  {
415  {
416  EqNP.s = IPS_ALERT;
417  IDSetNumber(&EqNP, "Error setting RA/DEC.");
418  return false;
419  }
420 
421  if (slewioptronHC8406() == 0)
422  {
423  EqNP.s = IPS_ALERT;
424  IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
425  slewError(1);
426  return false;
427  }
428  }
429 
431  LOGF_DEBUG("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
432  return true;
433 }
434 
435 bool ioptronHC8406::Sync(double ra, double dec)
436 {
437  char syncString[256];
438  int syncType = IUFindOnSwitchIndex(&SyncCMRSP);
439 
440  if (!isSimulation())
441  {
442  if (setObjectRA(PortFD, ra) < 0 || setObjectDEC(PortFD, dec) < 0)
443  {
444  EqNP.s = IPS_ALERT;
445  IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync.");
446  return false;
447  }
448 
449  bool syncOK = true;
450 
451  switch (syncType)
452  {
453  case USE_REGULAR_SYNC:
454  if (::Sync(PortFD, syncString) < 0)
455  syncOK = false;
456  break;
457 
458  case USE_CMR_SYNC:
459  if (ioptronHC8406SyncCMR(syncString) < 0)
460  syncOK = false;
461  break;
462 
463  default:
464  break;
465  }
466 
467  if (syncOK == false)
468  {
469  EqNP.s = IPS_ALERT;
470  IDSetNumber(&EqNP, "Synchronization failed.");
471  return false;
472  }
473 
474  }
475 
476  currentRA = ra;
477  currentDEC = dec;
478 
479  LOGF_DEBUG("%s Synchronization successful %s", (syncType == USE_REGULAR_SYNC ? "CM" : "CMR"), syncString);
480  LOG_INFO("Synchronization successful.");
482 
483  return true;
484 }
485 
486 int ioptronHC8406::ioptronHC8406SyncCMR(char *matchedObject)
487 {
488  const timespec timeout = {0, 10000000L};
489  int error_type;
490  int nbytes_write = 0;
491  int nbytes_read = 0;
492 
493  LOGF_DEBUG("CMD <%s>", ":CMR#");
494 
495  if ((error_type = tty_write_string(PortFD, ":CMR#", &nbytes_write)) != TTY_OK)
496  return error_type;
497 
498  if ((error_type = tty_read_section(PortFD, matchedObject, '#', 3, &nbytes_read)) != TTY_OK)
499  return error_type;
500 
501  matchedObject[nbytes_read - 1] = '\0';
502 
503  LOGF_DEBUG("RES <%s>", matchedObject);
504 
505  /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
506  nanosleep(&timeout, nullptr);
507 
508  tcflush(PortFD, TCIFLUSH);
509 
510  return 0;
511 }
512 
513 
514 int ioptronHC8406::slewioptronHC8406()
515 {
516  DEBUGF(DBG_SCOPE, "<%s>", __FUNCTION__);
517  char slewNum[2];
518  int error_type;
519  int nbytes_write = 0, nbytes_read = 0;
520 
521  DEBUGF(DBG_SCOPE, "CMD <%s>", ":MS#");
522 
523  if ((error_type = tty_write_string(PortFD, ":MS#", &nbytes_write)) != TTY_OK)
524  return error_type;
525 
526  error_type = tty_read(PortFD, slewNum, 1, 3, &nbytes_read);
527 
528  if (nbytes_read < 1)
529  {
530  DEBUGF(DBG_SCOPE, "RES ERROR <%d>", error_type);
531  return error_type;
532  }
533 
534  /* We don't need to read the string message, just return corresponding error code */
535  tcflush(PortFD, TCIFLUSH);
536 
537  DEBUGF(DBG_SCOPE, "RES <%c>", slewNum[0]);
538 
539  return slewNum[0];
540 }
541 
542 
543 
544 bool ioptronHC8406::updateTime(ln_date *utc, double utc_offset)
545 {
546  struct ln_zonedate ltm;
547 
548  if (isSimulation())
549  return true;
550 
551  ln_date_to_zonedate(utc, &ltm, utc_offset * 3600.0);
552 
553  JD = ln_get_julian_day(utc);
554 
555  LOGF_DEBUG("New JD is %.2f", JD);
556 
557  // Set Local Time
558  if (setLocalTime(PortFD, ltm.hours, ltm.minutes, ltm.seconds) < 0)
559  {
560  LOG_ERROR("Error setting local time.");
561  return false;
562  }
563 
564  if (setCalenderDate(PortFD, ltm.days, ltm.months, ltm.years) < 0)
565  {
566  LOG_ERROR("Error setting local date.");
567  return false;
568  }
569 
570  if (setioptronHC8406UTCOffset(utc_offset) < 0)
571  {
572  LOG_ERROR("Error setting UTC Offset.");
573  return false;
574  }
575 
576  return true;
577 }
578 
579 int ioptronHC8406::setCalenderDate(int fd, int dd, int mm, int yy)
580 {
581  char read_buffer[16];
582  char response[67];
583  char good_result[] = ioptronHC8406_CALDATE_RESULT;
584  int error_type;
585  int nbytes_write = 0, nbytes_read = 0;
586  yy = yy % 100;
587 
588  snprintf(read_buffer, sizeof(read_buffer), ":SC %02d:%02d:%02d#", mm, dd, yy);
589 
590  DEBUGF(DBG_SCOPE, "CMD <%s>", read_buffer);
591 
592  tcflush(fd, TCIFLUSH);
593  /* Sleep 100ms before flushing. This solves some issues with LX200 compatible devices. */
594  //usleep(10);
595  if ((error_type = tty_write_string(fd, read_buffer, &nbytes_write)) != TTY_OK)
596  return error_type;
597 
598  error_type = tty_read(fd, response, sizeof(response), ioptronHC8406_TIMEOUT, &nbytes_read);
599 
600  tcflush(fd, TCIFLUSH);
601 
602  if (nbytes_read < 1)
603  {
604  LOG_ERROR("Unable to read response");
605  return error_type;
606  }
607 
608  response[nbytes_read] = '\0';
609 
610  DEBUGF(DBG_SCOPE, "RES <%s>", response);
611 
612  if (strncmp(response, good_result, strlen(good_result)) == 0)
613  {
614  return 0;
615  }
616 
617 
618  tcflush(fd, TCIFLUSH);
619 
620  LOGF_DEBUG("Set date failed! Response: <%s>", response);
621 
622  return -1;
623 }
624 
625 bool ioptronHC8406::updateLocation(double latitude, double longitude, double elevation)
626 {
627  INDI_UNUSED(elevation);
628 
629  if (isSimulation())
630  return true;
631 
632  double final_longitude;
633 
634  if (longitude > 180)
635  final_longitude = longitude - 360.0;
636  else
637  final_longitude = longitude;
638 
639  if (!isSimulation() && setioptronHC8406Longitude(final_longitude) < 0)
640  {
641  LOG_ERROR("Error setting site longitude coordinates");
642  return false;
643  }
644 
645  if (!isSimulation() && setioptronHC8406Latitude(latitude) < 0)
646  {
647  LOG_ERROR("Error setting site latitude coordinates");
648  return false;
649  }
650 
651  char l[32], L[32];
652  fs_sexa(l, latitude, 3, 3600);
653  fs_sexa(L, longitude, 4, 3600);
654 
655  IDMessage(getDeviceName(), "Site location updated to Lat %.32s - Long %.32s", l, L);
656 
657  return true;
658 }
659 
660 int ioptronHC8406::setioptronHC8406Longitude(double Long)
661 {
662  int d, m, s;
663  char sign;
664  char temp_string[32];
665 
666  if (Long > 0)
667  sign = '+';
668  else
669  sign = '-';
670 
671  Long = 360 - Long;
672 
673  getSexComponents(Long, &d, &m, &s);
674 
675  snprintf(temp_string, sizeof(temp_string), ":Sg %c%03d*%02d:%02d#", sign, abs(d), m, s);
676 
677  return (setioptronHC8406StandardProcedure(PortFD, temp_string));
678 }
679 
680 int ioptronHC8406::setioptronHC8406Latitude(double Lat)
681 {
682  int d, m, s;
683  char sign;
684  char temp_string[32];
685 
686  if (Lat > 0)
687  sign = '+';
688  else
689  sign = '-';
690 
691  getSexComponents(Lat, &d, &m, &s);
692 
693  snprintf(temp_string, sizeof(temp_string), ":St %c%02d*%02d:%02d#", sign, abs(d), m, s);
694 
695  return (setioptronHC8406StandardProcedure(PortFD, temp_string));
696 }
697 
698 int ioptronHC8406::setioptronHC8406UTCOffset(double hours)
699 {
700  char temp_string[16];
701  char sign;
702  int h = 0, m = 0, s = 0;
703 
704  if (hours > 0)
705  sign = '+';
706  else
707  sign = '-';
708 
709  getSexComponents(hours, &h, &m, &s);
710 
711  snprintf(temp_string, sizeof(temp_string), ":SG %c%02d#", sign, abs(h));
712 
713  return (setioptronHC8406StandardProcedure(PortFD, temp_string));
714 }
715 
716 int ioptronHC8406::setioptronHC8406StandardProcedure(int fd, const char *data)
717 {
718  const timespec timeout = {0, 10000000L};
719  char bool_return[2];
720  int error_type = 0;
721  int nbytes_write = 0, nbytes_read = 0;
722 
723  DEBUGF(DBG_SCOPE, "CMD <%s>", data);
724 
725  if ((error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK)
726  return error_type;
727 
728  error_type = tty_read(fd, bool_return, 1, 5, &nbytes_read);
729 
730  // JM: Hack from Jon in the INDI forums to fix longitude/latitude settings failure
731 
732  nanosleep(&timeout, nullptr);
733  tcflush(fd, TCIFLUSH);
734  nanosleep(&timeout, nullptr);
735 
736 
737 
738  if (nbytes_read < 1)
739  return error_type;
740 
741  DEBUGF(DBG_SCOPE, "RES <%c>", bool_return[0]);
742 
743  if (bool_return[0] == '0')
744  {
745  DEBUGF(DBG_SCOPE, "CMD <%s> failed.", data);
746  return -1;
747  }
748 
749  DEBUGF(DBG_SCOPE, "CMD <%s> successful.", data);
750 
751  return 0;
752 }
753 
755 {
756  if (enabled)
757  {
758  LOG_WARN("<SetTrackEnabled> START TRACKING AT SIDERAL SPEED (:RT2#)");
759  return setioptronHC8406TrackMode(0);
760  }
761  else
762  {
763  LOG_WARN("<SetTrackEnabled> STOP TRACKING (:RT9#)");
764  return setioptronHC8406TrackMode(3);
765  }
766 }
767 
768 bool ioptronHC8406::SetTrackMode(uint8_t mode)
769 {
770  return (setioptronHC8406TrackMode(mode));
771 }
772 
773 int ioptronHC8406::setioptronHC8406TrackMode(int mode)
774 {
775 
776  char cmd[8];
777  int mmode = 0;
778  int error_type = 0;
779  int nbytes_write = 0 ;
780 
781  DEBUGF(DBG_SCOPE, "<%s>", __FUNCTION__);
782 
783  if (mode == 0 )
784  {
785  mmode = 2;
786  }
787  else if (mode == 1)
788  {
789  mmode = 1;
790  }
791  else if (mode == 2)
792  {
793  mmode = 0;
794  }
795  else if (mode == 3)
796  {
797  mmode = 9;
798  }
799  snprintf(cmd, 8, ":RT%d#", mmode);
800 
801  DEBUGF(DBG_SCOPE, "CMD <%s>", cmd);
802 
803  //None return value so just write cmd and exit without reading the response
804  if ((error_type = tty_write_string(PortFD, cmd, &nbytes_write)) != TTY_OK)
805  return error_type;
806 
807  return 1;
808 }
809 
811 {
812  DEBUGF(DBG_SCOPE, "<%s>", __FUNCTION__);
813  int error_type;
814  int nbytes_write = 0;
815 
816  if ((error_type = tty_write_string(PortFD, ":KA#", &nbytes_write)) != TTY_OK)
817  return error_type;
818  tcflush(PortFD, TCIFLUSH);
819  DEBUG(DBG_SCOPE, "CMD <:KA#>");
820 
822  LOG_INFO("Parking is in progress...");
823 
824  return true;
825 }
826 
828 {
829  SetParked(false);
830  return true;
831 }
832 
834 {
835  const timespec timeout = {1, 0L};
836 
837  //return true; //for debug
838 
839  if (!isConnected())
840  return false;
841 
842  if (isSimulation())
843  {
844  mountSim();
845  return true;
846  }
847 
848  switch (TrackState)
849  {
850  case SCOPE_IDLE:
851  LOG_WARN("<ReadScopeStatus> IDLE");
852  break;
853  case SCOPE_SLEWING:
854  LOG_WARN("<ReadScopeStatus> SLEWING");
855  break;
856  case SCOPE_TRACKING:
857  LOG_WARN("<ReadScopeStatus> TRACKING");
858  break;
859  case SCOPE_PARKING:
860  LOG_WARN("<ReadScopeStatus> PARKING");
861  break;
862  case SCOPE_PARKED:
863  LOG_WARN("<ReadScopeStatus> PARKED");
864  break;
865  default:
866  LOG_WARN("<ReadScopeStatus> UNDEFINED");
867  break;
868  }
869 
870  if (TrackState == SCOPE_SLEWING )
871  {
872  // Check if LX200 is done slewing
873  if (isSlewComplete())
874  {
875  nanosleep(&timeout, nullptr); //Wait until :MS# finish
876  if (IUFindSwitch(&CoordSP, "SYNC")->s == ISS_ON || IUFindSwitch(&CoordSP, "SLEW")->s == ISS_ON)
877  {
879  LOG_WARN("Slew is complete. IDLE");
880  SetTrackEnabled(false);
881  }
882  else
883  {
885  LOG_WARN("Slew is complete. TRACKING");
886  SetTrackEnabled(true);
887  }
888  }
889  }
890  else if (TrackState == SCOPE_PARKING)
891  {
892  // isSlewComplete() not work because is base on actual RA/DEC vs target RA/DEC. DO ALWAYS
893  if (true || isSlewComplete())
894  {
895  SetParked(true);
897  }
898  }
899 
901  {
902  EqNP.s = IPS_ALERT;
903  IDSetNumber(&EqNP, "Error reading RA/DEC.");
904  return false;
905  }
906 
908 
909  //sendScopeTime();
910  //syncSideOfPier();
911 
912  return true;
913 }
914 
915 void ioptronHC8406::mountSim()
916 {
917  static struct timeval ltv;
918  struct timeval tv;
919  double dt, da, dx;
920  int nlocked;
921 
922  /* update elapsed time since last poll, don't presume exactly POLLMS */
923  gettimeofday(&tv, nullptr);
924 
925  if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
926  ltv = tv;
927 
928  dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
929  ltv = tv;
930  da = SLEWRATE * dt;
931 
932  /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
933  switch (TrackState)
934  {
935  case SCOPE_TRACKING:
936  /* RA moves at sidereal, Dec stands still */
937  currentRA += (SIDRATE * dt / 15.);
938  break;
939 
940  case SCOPE_SLEWING:
941  case SCOPE_PARKING:
942  /* slewing - nail it when both within one pulse @ SLEWRATE */
943  nlocked = 0;
944 
945  dx = targetRA - currentRA;
946 
947  if (fabs(dx) <= da)
948  {
950  nlocked++;
951  }
952  else if (dx > 0)
953  currentRA += da / 15.;
954  else
955  currentRA -= da / 15.;
956 
957  dx = targetDEC - currentDEC;
958  if (fabs(dx) <= da)
959  {
961  nlocked++;
962  }
963  else if (dx > 0)
964  currentDEC += da;
965  else
966  currentDEC -= da;
967 
968  if (nlocked == 2)
969  {
970  if (TrackState == SCOPE_SLEWING)
972  else
973  SetParked(true);
974  }
975 
976  break;
977 
978  default:
979  break;
980  }
981 
983 }
984 
985 
986 
987 int ioptronHC8406::setioptronHC8406GuideRate(int rate)
988 {
989  return setMoveRate(rate, USE_GUIDE_SPEED);
990 }
991 
992 int ioptronHC8406::setioptronHC8406CenterRate(int rate)
993 {
994  return setMoveRate(rate, USE_CENTERING_SPEED);
995 }
996 
997 int ioptronHC8406::setioptronHC8406SlewRate(int rate)
998 {
999  return setMoveRate(rate, USE_SLEW_SPEED);
1000 }
1001 
1002 int ioptronHC8406::setioptronHC8406CursorMoveSpeed(int type)
1003 {
1004  return setMoveRate(-1, type);
1005 }
1006 
1007 int ioptronHC8406::setMoveRate(int rate, int move_type)
1008 {
1009  char cmd[16];
1010  int errcode = 0;
1011  char errmsg[MAXRBUF];
1012  int nbytes_written = 0;
1013 
1014  if (isSimulation())
1015  {
1016  return 0;
1017  }
1018 
1019  if (rate >= 0)
1020  {
1021  switch (move_type)
1022  {
1023  case USE_GUIDE_SPEED:
1024  snprintf(cmd, 16, ":RG%0d#", rate);
1025  break;
1026  case USE_CENTERING_SPEED:
1027  snprintf(cmd, 16, ":RC%0d#", rate);
1028  break;
1029  case USE_SLEW_SPEED:
1030  snprintf(cmd, 16, ":RS%0d#", rate); //NOT WORK!!
1031  break;
1032 
1033  default:
1034  break;
1035  }
1036  }
1037  else
1038  {
1039  switch (move_type)
1040  {
1041  case USE_GUIDE_SPEED:
1042  snprintf(cmd, 16, ":RG#");
1043  break;
1044  case USE_CENTERING_SPEED:
1045  snprintf(cmd, 16, ":RC#"); //NOT WORK!!
1046  break;
1047  case USE_SLEW_SPEED:
1048  snprintf(cmd, 16, ":RS#"); //NOT WORK!!
1049  break;
1050  default:
1051  break;
1052  }
1053  }
1054 
1055  LOGF_DEBUG("CMD (%s)", cmd);
1056 
1057 
1058  tcflush(PortFD, TCIFLUSH);
1059 
1060  if ((errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
1061  {
1062  tty_error_msg(errcode, errmsg, MAXRBUF);
1063  LOGF_ERROR("%s", errmsg);
1064  return errcode;
1065  }
1066 
1067  return 0;
1068 }
1069 
1070 
1071 void ioptronHC8406::syncSideOfPier()
1072 {
1073  const char *cmd = ":pS#";
1074  // Response
1075  char response[16] = { 0 };
1076  int rc = 0, nbytes_read = 0, nbytes_written = 0;
1077 
1078  LOGF_DEBUG("CMD: <%s>", cmd);
1079 
1080  tcflush(PortFD, TCIOFLUSH);
1081 
1082  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
1083  {
1084  char errmsg[256];
1085  tty_error_msg(rc, errmsg, 256);
1086  LOGF_ERROR("Error writing to device %s (%d)", errmsg, rc);
1087  return;
1088  }
1089 
1090  // Read Side
1091  if ((rc = tty_read_section(PortFD, response, '#', 3, &nbytes_read)) != TTY_OK)
1092  {
1093  char errmsg[256];
1094  tty_error_msg(rc, errmsg, 256);
1095  LOGF_ERROR("Error reading from device %s (%d)", errmsg, rc);
1096  return;
1097  }
1098 
1099  response[nbytes_read - 1] = '\0';
1100 
1101  tcflush(PortFD, TCIOFLUSH);
1102 
1103  LOGF_DEBUG("RES: <%s>", response);
1104 
1105  if (!strcmp(response, "East"))
1107  else
1109 
1110 }
1111 
1113 {
1115 
1116  IUSaveConfigSwitch(fp, &SyncCMRSP);
1117 
1118  return true;
1119 }
1120 
1121 int ioptronHC8406::getCommandString(int fd, char *data, const char *cmd)
1122 {
1123  char *term;
1124  int error_type;
1125  int nbytes_write = 0, nbytes_read = 0;
1126 
1127 
1128  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
1129  return error_type;
1130 
1131  error_type = tty_read_section(fd, data, '#', ioptronHC8406_TIMEOUT, &nbytes_read);
1132  tcflush(fd, TCIFLUSH);
1133 
1134  if (error_type != TTY_OK)
1135  return error_type;
1136 
1137  term = strchr(data, '#');
1138  if (term)
1139  *term = '\0';
1140 
1141 
1142 
1143  return 0;
1144 
1145 }
1146 
1148 {
1149  char cdate[32] = {0};
1150  double ctime;
1151  int h, m, s;
1152  int utc_h, utc_m, utc_s;
1153  double lx200_utc_offset = 0;
1154  char utc_offset_res[32] = {0};
1155  int day, month, year, result;
1156  struct tm ltm;
1157  struct tm utm;
1158 
1159  memset(&ltm, 0, sizeof(ltm));
1160  memset(&utm, 0, sizeof(utm));
1161 
1162  time_t time_epoch;
1163 
1164  if (isSimulation())
1165  {
1166  snprintf(cdate, 32, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
1167  IDLog("Telescope ISO date and time: %s\n", cdate);
1168  IUSaveText(&TimeT[0], cdate);
1169  IUSaveText(&TimeT[1], "3");
1170  TimeTP.s = IPS_OK;
1171  IDSetText(&TimeTP, nullptr);
1172  return true;
1173  }
1174 
1175  //getCommandSexa(PortFD, &lx200_utc_offset, ":GG#");
1176  //tcflush(PortFD, TCIOFLUSH);
1177  getCommandString(PortFD, utc_offset_res, ":GG#");
1178 
1179  f_scansexa(utc_offset_res, &lx200_utc_offset);
1180  result = sscanf(utc_offset_res, "%d%*c%d%*c%d", &utc_h, &utc_m, &utc_s);
1181  if (result != 3)
1182  {
1183  LOG_ERROR("Error reading UTC offset from Telescope.");
1184  return false;
1185  }
1186  LOGF_DEBUG("<VAL> UTC offset: %d:%d:%d --->%g", utc_h, utc_m, utc_s, lx200_utc_offset);
1187  // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
1188  LOGF_DEBUG("<VAL> UTC offset str: %s", utc_offset_res);
1189  IUSaveText(&TimeT[1], utc_offset_res);
1190  //IUSaveText(&TimeT[1], lx200_utc_offset);
1191 
1192  getLocalTime24(PortFD, &ctime);
1193  getSexComponents(ctime, &h, &m, &s);
1194 
1195  getCalendarDate(PortFD, cdate);
1196  result = sscanf(cdate, "%d%*c%d%*c%d", &year, &month, &day);
1197  if (result != 3)
1198  {
1199  LOG_ERROR("Error reading date from Telescope.");
1200  return false;
1201  }
1202 
1203  // Let's fill in the local time
1204  ltm.tm_sec = s;
1205  ltm.tm_min = m;
1206  ltm.tm_hour = h;
1207  ltm.tm_mday = day;
1208  ltm.tm_mon = month - 1;
1209  ltm.tm_year = year - 1900;
1210  ltm.tm_isdst = 0;
1211 
1212  // Get time epoch
1213  time_epoch = mktime(&ltm);
1214 
1215  // Convert to TimeT
1216  //time_epoch -= (int)(atof(TimeT[1].text) * 3600.0);
1217  time_epoch -= (int)(lx200_utc_offset * 3600.0);
1218 
1219  // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time
1220  localtime_r(&time_epoch, &utm);
1221 
1222  /* Format it into ISO 8601 */
1223  strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm);
1224  IUSaveText(&TimeT[0], cdate);
1225 
1226  LOGF_DEBUG("Mount controller Local Time: %02d:%02d:%02d", h, m, s);
1227  LOGF_DEBUG("Mount controller UTC Time: %s", TimeT[0].text);
1228 
1229  // Let's send everything to the client
1230  TimeTP.s = IPS_OK;
1231  IDSetText(&TimeTP, nullptr);
1232  return true;
1233 }
1234 
1235 int ioptronHC8406::SendPulseCmd(int8_t direction, uint32_t duration_msec)
1236 {
1237  const timespec timeout = {1, 0L};
1238  int rc = 0, nbytes_written = 0;
1239  char cmd[20];
1240  uint32_t duration_left = 0, duration_now = duration_msec;
1241  if (duration_msec > 999)
1242  {
1243  duration_now = 999; //limited to 999
1244  duration_left = duration_msec - duration_now; //pending ms
1245  }
1246  else
1247  {
1248  duration_left = 0;
1249  LOGF_DEBUG("Pulse %d <999 Sent only one", duration_msec);
1250  }
1251 
1252  switch (direction)
1253  {
1254  case LX200_NORTH:
1255  sprintf(cmd, ":Mn%03d#", duration_now);
1256  break;
1257  case LX200_SOUTH:
1258  sprintf(cmd, ":Ms%03d#", duration_now);
1259  break;
1260  case LX200_EAST:
1261  sprintf(cmd, ":Me%03d#", duration_now);
1262  break;
1263  case LX200_WEST:
1264  sprintf(cmd, ":Mw%03d#", duration_now);
1265  break;
1266  default:
1267  return 1;
1268  }
1269  LOGF_DEBUG("CMD <%s>", cmd);
1270 
1271  if ((rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
1272  {
1273  char errmsg[256];
1274  tty_error_msg(rc, errmsg, 256);
1275  LOGF_ERROR("Error writing to device %s (%d)", errmsg, rc);
1276  return 1;
1277  }
1278  tcflush(PortFD, TCIFLUSH);
1279 
1280  if (duration_left != 0)
1281  {
1282  LOGF_DEBUG("pulse guide. Pulse >999. ms left:%d", duration_left);
1283  nanosleep(&timeout, nullptr); //wait until the previous one has fineshed
1284  return SendPulseCmd(direction, duration_left);
1285  }
1286  return 0;
1287 }
1288 
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
TelescopeStatus TrackState
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
ITextVectorProperty TimeTP
ISwitchVectorProperty CoordSP
ISwitchVectorProperty TrackModeSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
ISwitchVectorProperty MovementWESP
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void slewError(int slewCode)
virtual bool sendScopeLocation()
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void setLX200Capability(uint32_t cap)
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool sendScopeTime() override
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual const char * getDefaultName() override
virtual bool Park() override
Park the telescope to its home position.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual bool checkConnection() override
virtual int SendPulseCmd(int8_t direction, uint32_t duration_msec) override
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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 saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool isSlewComplete() override
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void getBasicData() override
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
virtual bool ReadScopeStatus() override
Read telescope status.
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.
#define setLocalTime(fd, x, y, z)
Definition: ieq45driver.h:141
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
@ 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
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Definition: indicom.c:205
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void IDLog(const char *fmt,...)
Definition: indicom.c:316
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
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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[].
Definition: indicom.c:141
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
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 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 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
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indidevapi.c:76
#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 IDMessage(const char *dev, const char *fmt,...)
Definition: indidriver.c:960
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
#define LOG_WARN(txt)
Definition: indilogger.h:73
#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
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
#define MAXRBUF
Definition: indiserver.cpp:102
int fd
Definition: intelliscope.c:43
#define SIDRATE
#define ioptronHC8406_TIMEOUT
#define SLEWRATE
#define ioptronHC8406_CALDATE_RESULT
int setObjectRA(int fd, double ra, bool addSpace)
int setObjectDEC(int fd, double dec, bool addSpace)
int checkLX200EquatorialFormat(int fd)
int abortSlew(int fd)
int setCalenderDate(int fd, int dd, int mm, int yy, bool addSpace)
int getCalendarDate(int fd, char *date)
int getCommandString(int fd, char *data, const char *cmd)
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
@ LX200_WEST
Definition: lx200driver.h:42
@ LX200_SOUTH
Definition: lx200driver.h:44
@ LX200_NORTH
Definition: lx200driver.h:41
@ LX200_EAST
Definition: lx200driver.h:43
#define getLocalTime24(fd, x)
Definition: lx200driver.h:122
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:371