Instrument Neutral Distributed Interface INDI  1.9.5
lx200driver.cpp
Go to the documentation of this file.
1 #if 0
2 LX200 Driver
3 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 
5 This library is free software;
6 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;
9 either
10 version 2.1 of the License, or (at your option) any later version.
11 
12 This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY;
14 without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library;
20 if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
22 
23 #endif
24 
25 #include "lx200driver.h"
26 
27 #include "indicom.h"
28 #include "indilogger.h"
29 
30 #include <cstring>
31 #include <unistd.h>
32 
33 #ifndef _WIN32
34 #include <termios.h>
35 #endif
36 
37 #ifdef __FreeBSD__
38 #include <string.h>
39 #endif
40 
41 /* Add mutex */
42 
43 #include <mutex>
44 
45 #define LX200_TIMEOUT 5 /* FD timeout in seconds */
46 #define RB_MAX_LEN 64
47 
48 
49 int eq_format; /* For possible values see enum TEquatorialFormat */
50 int geo_format = LX200_GEO_SHORT_FORMAT; /* For possible values see enum TGeographicFormat */
52 /* ESN DEBUG */
53 unsigned int DBG_SCOPE = 8;
54 
55 /* Add mutex to communications */
56 std::mutex lx200CommsLock;
57 
58 void setLX200Debug(const char *deviceName, unsigned int debug_level)
59 {
60  strncpy(lx200Name, deviceName, MAXINDIDEVICE);
61  DBG_SCOPE = debug_level;
62 }
63 
64 /**************************************************************************
65  Diagnostics
66  **************************************************************************/
67 char ACK(int fd);
68 int check_lx200_connection(int fd);
69 
70 /**************************************************************************
71  Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure
72  **************************************************************************/
73 
74 /* Get Double from Sexagisemal */
75 int getCommandSexa(int fd, double *value, const char *cmd);
76 /* Get String */
77 int getCommandString(int fd, char *data, const char *cmd);
78 /* Get Int */
79 int getCommandInt(int fd, int *value, const char *cmd);
80 /* Get tracking frequency */
81 int getTrackFreq(int fd, double *value);
82 /* Get site Latitude */
83 int getSiteLatitude(int fd, int *dd, int *mm, double *ssf);
84 /* Get site Longitude */
85 int getSiteLongitude(int fd, int *ddd, int *mm, double *ssf);
86 /* Get Calender data */
87 int getCalendarDate(int fd, char *date);
88 /* Get site Name */
89 int getSiteName(int fd, char *siteName, int siteNum);
90 /* Get Home Search Status */
91 int getHomeSearchStatus(int fd, int *status);
92 /* Get OTA Temperature */
93 int getOTATemp(int fd, double *value);
94 /* Get time format: 12 or 24 */
95 int getTimeFormat(int fd, int *format);
96 
97 /**************************************************************************
98  Set Commands
99  **************************************************************************/
100 
101 /* Set Int */
102 int setCommandInt(int fd, int data, const char *cmd);
103 /* Set Sexagesimal */
104 int setCommandXYZ(int fd, int x, int y, int z, const char *cmd);
105 /* Common routine for Set commands */
106 int setStandardProcedure(int fd, const char *writeData);
107 /* Set Slew Mode */
108 int setSlewMode(int fd, int slewMode);
109 /* Set Alignment mode */
110 int setAlignmentMode(int fd, unsigned int alignMode);
111 /* Set Object RA */
112 int setObjectRA(int fd, double ra);
113 /* set Object DEC */
114 int setObjectDEC(int fd, double dec);
115 /* Set Calendar date */
116 int setCalenderDate(int fd, int dd, int mm, int yy);
117 /* Set UTC offset */
118 int setUTCOffset(int fd, double hours);
119 /* Set Track Freq */
120 int setTrackFreq(int fd, double trackF);
121 /* Set current site longitude */
122 int setSiteLongitude(int fd, double CartographicLongitude);
123 /* Set current site latitude */
124 int setSiteLatitude(int fd, double Lat);
125 /* Set Object Azimuth */
126 int setObjAz(int fd, double az);
127 /* Set Object Altitude */
128 int setObjAlt(int fd, double alt);
129 /* Set site name */
130 int setSiteName(int fd, char *siteName, int siteNum);
131 /* Set maximum slew rate */
132 int setMaxSlewRate(int fd, int slewRate);
133 /* Set focuser motion */
134 int setFocuserMotion(int fd, int motionType);
135 /* Set focuser speed mode */
136 int setFocuserSpeedMode(int fd, int speedMode);
137 /* Set minimum elevation limit */
138 int setMinElevationLimit(int fd, int min);
139 /* Set maximum elevation limit */
140 int setMaxElevationLimit(int fd, int max);
141 
142 /**************************************************************************
143  Motion Commands
144  **************************************************************************/
145 /* Slew to the selected coordinates */
146 int Slew(int fd);
147 /* Synchronize to the selected coordinates and return the matching object if any */
148 int Sync(int fd, char *matchedObject);
149 /* Abort slew in all axes */
150 int abortSlew(int fd);
151 /* Move into one direction, two valid directions can be stacked */
152 int MoveTo(int fd, int direction);
153 /* Half movement in a particular direction */
154 int HaltMovement(int fd, int direction);
155 /* Select the tracking mode */
156 int selectTrackingMode(int fd, int trackMode);
157 /* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */
158 int SendPulseCmd(int fd, int direction, uint32_t duration_msec);
159 
160 /**************************************************************************
161  Other Commands
162  **************************************************************************/
163 /* Determines LX200 RA/DEC format, tries to set to long if found short */
165 /* return the eq_format enum value */
167 /* return the geo_format enum value */
169 /* Select a site from the LX200 controller */
170 int selectSite(int fd, int siteNum);
171 /* Select a catalog object */
172 int selectCatalogObject(int fd, int catalog, int NNNN);
173 /* Select a sub catalog */
174 int selectSubCatalog(int fd, int catalog, int subCatalog);
175 
177 {
178  const struct timespec timeout = {0, 50000000L};
179  int i = 0;
180  char ack[1] = { 0x06 };
181  char MountAlign[64];
182  int nbytes_read = 0;
183 
184  DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Testing telescope connection using ACK...");
185 
186 /* Add mutex */
187  std::unique_lock<std::mutex> guard(lx200CommsLock);
188 
189  if (in_fd <= 0)
190  return -1;
191 
192  for (i = 0; i < 2; i++)
193  {
194  if (write(in_fd, ack, 1) < 0)
195  return -1;
196  tty_read(in_fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read);
197  if (nbytes_read == 1)
198  {
199  DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Testing successful!");
200  return 0;
201  }
202  nanosleep(&timeout, nullptr);
203  }
204 
205  DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Failure. Telescope is not responding to ACK!");
206  return -1;
207 }
208 
209 /**********************************************************************
210 * GET
211 **********************************************************************/
212 
213 char ACK(int fd)
214 {
215  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
216 
217  char ack[1] = { 0x06 };
218  char MountAlign[2];
219  int nbytes_write = 0, nbytes_read = 0, error_type;
220 
221 /* Add mutex */
222  std::unique_lock<std::mutex> guard(lx200CommsLock);
223 
224  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%#02X>", ack[0]);
225 
226  nbytes_write = write(fd, ack, 1);
227 
228  if (nbytes_write < 0)
229  return -1;
230 
231  error_type = tty_read(fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read);
232 
233  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", MountAlign[0]);
234 
235  if (nbytes_read == 1)
236  return MountAlign[0];
237  else
238  return error_type;
239 }
240 
241 int getCommandSexa(int fd, double *value, const char *cmd)
242 {
243  char read_buffer[RB_MAX_LEN]={0};
244  int error_type;
245  int nbytes_write = 0, nbytes_read = 0;
246 
247 /* Add mutex */
248  std::unique_lock<std::mutex> guard(lx200CommsLock);
249 
250  tcflush(fd, TCIFLUSH);
251 
252  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
253 
254  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
255  return error_type;
256 
257  error_type = tty_nread_section(fd, read_buffer,RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
258  tcflush(fd, TCIFLUSH);
259  if (error_type != TTY_OK)
260  return error_type;
261 
262  read_buffer[nbytes_read - 1] = '\0';
263 
264  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
265 
266  if (f_scansexa(read_buffer, value))
267  {
268  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response");
269  return -1;
270  }
271 
272  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value);
273 
274  tcflush(fd, TCIFLUSH);
275  return 0;
276 }
277 
278 int getCommandInt(int fd, int *value, const char *cmd)
279 {
280  char read_buffer[RB_MAX_LEN]={0};
281  float temp_number;
282  int error_type;
283  int nbytes_write = 0, nbytes_read = 0;
284 
285 /* Add mutex */
286  std::unique_lock<std::mutex> guard(lx200CommsLock);
287 
288  tcflush(fd, TCIFLUSH);
289 
290  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
291 
292  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
293  return error_type;
294 
295  error_type = tty_nread_section(fd, read_buffer,RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
296  tcflush(fd, TCIFLUSH);
297  if (error_type != TTY_OK)
298  return error_type;
299 
300  read_buffer[nbytes_read - 1] = '\0';
301 
302  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
303 
304  /* Float */
305  if (strchr(read_buffer, '.'))
306  {
307  if (sscanf(read_buffer, "%f", &temp_number) != 1)
308  return -1;
309 
310  *value = static_cast<int>(temp_number);
311  }
312  /* Int */
313  else if (sscanf(read_buffer, "%d", value) != 1)
314  return -1;
315 
316  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d]", *value);
317 
318  return 0;
319 }
320 
321 int getCommandString(int fd, char *data, const char *cmd)
322 {
323  char *term;
324  int error_type;
325  int nbytes_write = 0, nbytes_read = 0;
326 
327  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
328 
329 /* Add mutex */
330  std::unique_lock<std::mutex> guard(lx200CommsLock);
331 
332  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
333  return error_type;
334 
335  error_type = tty_nread_section(fd, data, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
336  tcflush(fd, TCIFLUSH);
337 
338  if (error_type != TTY_OK)
339  return error_type;
340 
341  term = strchr(data, '#');
342  if (term)
343  *term = '\0';
344 
345  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", data);
346 
347  return 0;
348 }
349 
351 {
352  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
353 /* update for classic lx200, total string returned is 33 bytes */
354  char data[33] = { 0 };
355  int error_type;
356  int nbytes_write = 0, nbytes_read = 0;
357  const char *cmd = ":D#";
358 
359 /* update for slew complete lx200 classic 3.2. roms */
360  int i;
361 
362 
363  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
364 
365 /* Add mutex */
366  std::unique_lock<std::mutex> guard(lx200CommsLock);
367 
368  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
369  return error_type;
370 
371  error_type = tty_nread_section(fd, data, 33, '#', LX200_TIMEOUT, &nbytes_read);
372  tcflush(fd, TCIOFLUSH);
373 
374  if (error_type != TTY_OK)
375  return error_type;
376 
377  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", data);
378 /* update for slewComplete
379 
380  The below should handle classic lx200, autostar and autostar 2
381  classic returns string of 33 bytes, and non space (0x20) before terminator is not done yet
382  autostar and autostar 2 return a few bytes, with '#' terminator
383  first char
384 */
385  for(i=0;i<33;i++) {
386  if(data[i] == '#') return 1;
387  if(data[i] != 0x20) return 0;
388  }
389  return 1;
390 /* out for slewComplete update
391  if (data[0] == '#')
392  return 1;
393  else
394  return 0;
395 END out for slewComplete update */
396 }
397 
398 int getCalendarDate(int fd, char *date)
399 {
400  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
401  int dd, mm, yy, YYYY;
402  int error_type;
403  int nbytes_read = 0;
404  char mell_prefix[3]={0};
405  int len = 0;
406 
407 /* Add mutex */
408 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
409 
410  if ((error_type = getCommandString(fd, date, ":GC#")))
411  return error_type;
412  len = strnlen(date, 32);
413  if (len == 10)
414  {
415  /* 10Micron Ultra Precision mode calendar date format is YYYY-MM-DD */
416  nbytes_read = sscanf(date, "%4d-%2d-%2d", &YYYY, &mm, &dd);
417  if (nbytes_read < 3)
418  return -1;
419  /* We're done, date is already in ISO format */
420  }
421  else
422  {
423  /* Meade format is MM/DD/YY */
424  nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy);
425  if (nbytes_read < 3)
426  return -1;
427  /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/
428  if (yy > 50)
429  strncpy(mell_prefix, "19", 3);
430  else
431  strncpy(mell_prefix, "20", 3);
432  /* We need to have it in YYYY-MM-DD ISO format */
433  snprintf(date, 32, "%s%02d-%02d-%02d", mell_prefix, yy, mm, dd);
434  }
435  return (0);
436 }
437 
438 int getTimeFormat(int fd, int *format)
439 {
440  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
441  char read_buffer[RB_MAX_LEN]={0};
442  int error_type;
443  int nbytes_write = 0, nbytes_read = 0;
444  int tMode;
445 
446  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Gc#");
447 
448 /* Add mutex */
449  std::unique_lock<std::mutex> guard(lx200CommsLock);
450 
451  if ((error_type = tty_write_string(fd, ":Gc#", &nbytes_write)) != TTY_OK)
452  return error_type;
453 
454  if ((error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
455  return error_type;
456 
457  tcflush(fd, TCIFLUSH);
458 
459  if (nbytes_read < 1)
460  return error_type;
461 
462  read_buffer[nbytes_read - 1] = '\0';
463 
464  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
465 
466  // The Losmandy Gemini puts () around it's time format
467  if (strstr(read_buffer, "("))
468  nbytes_read = sscanf(read_buffer, "(%d)", &tMode);
469  else
470  nbytes_read = sscanf(read_buffer, "%d", &tMode);
471 
472  if (nbytes_read < 1)
473  return -1;
474  else
475  *format = tMode;
476 
477  return 0;
478 }
479 
480 int getSiteName(int fd, char *siteName, int siteNum)
481 {
482  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
483  char *term;
484  int error_type;
485  int nbytes_write = 0, nbytes_read = 0;
486 
487 /* Add mutex */
488  std::unique_lock<std::mutex> guard(lx200CommsLock);
489 
490  switch (siteNum)
491  {
492  case 1:
493  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GM#");
494  if ((error_type = tty_write_string(fd, ":GM#", &nbytes_write)) != TTY_OK)
495  return error_type;
496  break;
497  case 2:
498  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GN#");
499  if ((error_type = tty_write_string(fd, ":GN#", &nbytes_write)) != TTY_OK)
500  return error_type;
501  break;
502  case 3:
503  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GO#");
504  if ((error_type = tty_write_string(fd, ":GO#", &nbytes_write)) != TTY_OK)
505  return error_type;
506  break;
507  case 4:
508  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GP#");
509  if ((error_type = tty_write_string(fd, ":GP#", &nbytes_write)) != TTY_OK)
510  return error_type;
511  break;
512  default:
513  return -1;
514  }
515 
516  error_type = tty_nread_section(fd, siteName, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
517  tcflush(fd, TCIFLUSH);
518 
519  if (nbytes_read < 1)
520  return error_type;
521 
522  siteName[nbytes_read - 1] = '\0';
523 
524  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", siteName);
525 
526  term = strchr(siteName, ' ');
527  if (term)
528  *term = '\0';
529 
530  term = strchr(siteName, '<');
531  if (term)
532  strcpy(siteName, "unused site");
533 
534  DEBUGFDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Site Name <%s>", siteName);
535 
536  return 0;
537 }
538 
539 int getSiteLatitude(int fd, int *dd, int *mm, double *ssf)
540 {
541  return getSiteLatitudeAlt( fd, dd, mm, ssf, ":Gt#");
542 }
543 
544 // Meade classic handset defines longitude as 0 to 360 WESTWARD. However,
545 // Meade API expresses East Longitudes as negative, West Longitudes as positive.
546 // Source: https://www.meade.com/support/LX200CommandSet.pdf from 2002 at :Gg#
547 // (And also 10Micron has East Longitudes expressed as negative.)
548 // Also note that this is the opposite of cartography where East is positive.
549 int getSiteLongitude(int fd, int *ddd, int *mm, double *ssf)
550 {
551  return getSiteLongitudeAlt(fd, ddd, mm, ssf, ":Gg#");
552 }
553 
554 
555 int getSiteLatitudeAlt(int fd, int *dd, int *mm, double *ssf, const char *cmd)
556 {
557  // :Gt# from 10Micron docs explaining the extensions to the standard LX200 protocol.
558  // Get current site latitude.
559  // Returns the latitude of the current site formatted as follows:
560  // Emulation and precision Return value
561  // Any emulation, low precision sDD*MM# (sign, degrees, minutes)
562  // LX200 emulation, high precision sDD*MM# (sign, degrees, minutes)
563  // Extended emulation, high precision sDD*MM:SS# (sign, degrees, arcminutes, arcseconds)
564  // Any emulation, ultra precision sDD:MM:SS.S# (sign, degrees, arcminutes, arcseconds, tenths of arcsecond)
565  // Positive implies north latitude.
566  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
567  char read_buffer[RB_MAX_LEN]={0};
568  int error_type;
569  int nbytes_write = 0, nbytes_read = 0;
570 
571  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
572 
573  /* Add mutex */
574  std::unique_lock<std::mutex> guard(lx200CommsLock);
575 
576  tcflush(fd, TCIFLUSH);
577 
578  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
579  return error_type;
580 
581  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
582 
583  tcflush(fd, TCIFLUSH);
584 
585  if (nbytes_read < 1)
586  return error_type;
587 
588  read_buffer[nbytes_read - 1] = '\0';
589 
590  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
591 
592  *ssf = 0.0;
593  if (sscanf(read_buffer, "%d%*c%d:%lf", dd, mm, ssf) < 2)
594  {
595  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unable to parse %s response", cmd);
596  return -1;
597  }
598 
599  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d,%d,%.1lf]", *dd, *mm, *ssf);
600 
601  int new_geo_format;
602  switch (nbytes_read) {
603  case 9:
604  case 10:
605  new_geo_format = LX200_GEO_LONG_FORMAT;
606  break;
607  case 11:
608  case 12:
609  new_geo_format = LX200_GEO_LONGER_FORMAT;
610  break;
611  default:
612  new_geo_format = LX200_GEO_SHORT_FORMAT;
613  break;
614  }
615  if (new_geo_format != geo_format)
616  {
617  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Updated geographic precision from setting %d to %d", geo_format, new_geo_format);
618  geo_format = new_geo_format;
619  }
620 
621  return 0;
622 }
623 
624 // Meade classic handset defines longitude as 0 to 360 WESTWARD. However,
625 // Meade API expresses East Longitudes as negative, West Longitudes as positive.
626 // Source: https://www.meade.com/support/LX200CommandSet.pdf from 2002 at :Gg#
627 // (And also 10Micron has East Longitudes expressed as negative.)
628 // Also note that this is the opposite of cartography where East is positive.
629 int getSiteLongitudeAlt(int fd, int *ddd, int *mm, double *ssf, const char *cmd)
630 {
631  // :Gg# from 10Micron docs explaining the extensions to the standard LX200 protocol.
632  // Get current site longitude.
633  // Note: East Longitudes are expressed as negative.
634  // Returns the current site longitude formatted as follows:
635  // Emulation and precision Return value
636  // Any emulation, low precision or LX200 sDDD*MM# (sign, degrees, arcminutes)
637  // emulation, high precision
638  // Extended emulation, high precision sDDD*MM:SS# (sign, degrees, arcminutes, arcseconds)
639  // Any emulation, ultra precision sDDD:MM:SS.S# (sign, degrees, arcminutes, arcseconds, tenths of arcsecond)
640 
641  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
642  char read_buffer[RB_MAX_LEN]={0};
643  int error_type;
644  int nbytes_write = 0, nbytes_read = 0;
645 
646  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
647 
648  /* Add mutex */
649  std::unique_lock<std::mutex> guard(lx200CommsLock);
650 
651  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
652  return error_type;
653 
654  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
655 
656  tcflush(fd, TCIFLUSH);
657 
658  if (nbytes_read < 1)
659  return error_type;
660 
661  read_buffer[nbytes_read - 1] = '\0';
662 
663  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
664 
665  *ssf = 0.0;
666  if (sscanf(read_buffer, "%d%*c%d:%lf", ddd, mm, ssf) < 2)
667  {
668  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unable to parse %s response", cmd);
669  return -1;
670  }
671  *ddd *= -1.0; // Convert LX200Longitude to CartographicLongitude
672 
673  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL in CartographicLongitude format [%d,%d,%.1lf]", *ddd, *mm, *ssf);
674 
675  int new_geo_format;
676  switch (nbytes_read) {
677  case 10:
678  case 11:
679  new_geo_format = LX200_GEO_LONG_FORMAT;
680  break;
681  case 12:
682  case 13:
683  new_geo_format = LX200_GEO_LONGER_FORMAT;
684  break;
685  default:
686  new_geo_format = LX200_GEO_SHORT_FORMAT;
687  break;
688  }
689  if (new_geo_format != geo_format)
690  {
691  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Updated geographic precision from setting %d to %d", geo_format, new_geo_format);
692  geo_format = new_geo_format;
693  }
694 
695  return 0;
696 }
697 
698 
699 
700 
701 
702 
703 int getTrackFreq(int fd, double *value)
704 {
705  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
706  float Freq;
707  char read_buffer[RB_MAX_LEN]={0};
708  int error_type;
709  int nbytes_write = 0, nbytes_read = 0;
710 
711  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GT#");
712 
713 /* Add mutex */
714  std::unique_lock<std::mutex> guard(lx200CommsLock);
715 
716  if ((error_type = tty_write_string(fd, ":GT#", &nbytes_write)) != TTY_OK)
717  return error_type;
718 
719  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
720  tcflush(fd, TCIFLUSH);
721 
722  if (nbytes_read < 1)
723  return error_type;
724 
725  read_buffer[nbytes_read] = '\0';
726 
727  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
728 
729  if (sscanf(read_buffer, "%f#", &Freq) < 1)
730  {
731  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response");
732  return -1;
733  }
734 
735  *value = static_cast<double>(Freq);
736 
737  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value);
738 
739  return 0;
740 }
741 
742 int getHomeSearchStatus(int fd, int *status)
743 {
744  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
745  char read_buffer[RB_MAX_LEN]={0};
746  int error_type;
747  int nbytes_write = 0, nbytes_read = 0;
748 
749  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":h?#");
750 
751 /* Add mutex */
752  std::unique_lock<std::mutex> guard(lx200CommsLock);
753 
754  if ((error_type = tty_write_string(fd, ":h?#", &nbytes_write)) != TTY_OK)
755  return error_type;
756 
757  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
758  tcflush(fd, TCIFLUSH);
759 
760  if (nbytes_read < 1)
761  return error_type;
762 
763  read_buffer[1] = '\0';
764 
765  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
766 
767  if (read_buffer[0] == '0')
768  *status = 0;
769  else if (read_buffer[0] == '1')
770  *status = 1;
771  else if (read_buffer[0] == '2')
772  *status = 1;
773 
774  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d]", *status);
775 
776  return 0;
777 }
778 
779 int getOTATemp(int fd, double *value)
780 {
781  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
782  char read_buffer[RB_MAX_LEN]={0};
783  int error_type;
784  int nbytes_write = 0, nbytes_read = 0;
785  float temp;
786 
787  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":fT#");
788 
789 /* Add mutex */
790  std::unique_lock<std::mutex> guard(lx200CommsLock);
791 
792  if ((error_type = tty_write_string(fd, ":fT#", &nbytes_write)) != TTY_OK)
793  return error_type;
794 
795  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
796 
797  if (nbytes_read < 1)
798  return error_type;
799 
800  read_buffer[nbytes_read - 1] = '\0';
801 
802  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
803 
804  if (sscanf(read_buffer, "%f", &temp) < 1)
805  {
806  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response");
807  return -1;
808  }
809 
810  *value = static_cast<double>(temp);
811 
812  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value);
813 
814  return 0;
815 }
816 
817 /**********************************************************************
818 * SET
819 **********************************************************************/
820 
821 int setStandardProcedure(int fd, const char *data)
822 {
823  char bool_return[2];
824  int error_type;
825  int nbytes_write = 0, nbytes_read = 0;
826 
827  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", data);
828 
829 /* Add mutex */
830  std::unique_lock<std::mutex> guard(lx200CommsLock);
831 
832  tcflush(fd, TCIFLUSH);
833 
834  if ((error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK)
835  return error_type;
836 
837  error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read);
838 
839  tcflush(fd, TCIFLUSH);
840 
841  if (nbytes_read < 1)
842  return error_type;
843 
844  if (bool_return[0] == '0')
845  {
846  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> failed.", data);
847  return -1;
848  }
849 
850  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> successful.", data);
851 
852  return 0;
853 }
854 
855 int setCommandInt(int fd, int data, const char *cmd)
856 {
857  char read_buffer[RB_MAX_LEN]={0};
858  int error_type;
859  int nbytes_write = 0;
860 
861 /* Add mutex */
862  std::unique_lock<std::mutex> guard(lx200CommsLock);
863 
864  snprintf(read_buffer, sizeof(read_buffer), "%s%d#", cmd, data);
865 
866  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", read_buffer);
867 
868  tcflush(fd, TCIFLUSH);
869 
870  if ((error_type = tty_write_string(fd, read_buffer, &nbytes_write)) != TTY_OK)
871  {
872  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> failed.", read_buffer);
873  return error_type;
874  }
875 
876  tcflush(fd, TCIFLUSH);
877 
878  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> successful.", read_buffer);
879 
880  return 0;
881 }
882 
884 {
885  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
886  char read_buffer[RB_MAX_LEN]={0};
887 
888  snprintf(read_buffer, sizeof(read_buffer), ":Sh%02d#", min);
889 
890  return (setStandardProcedure(fd, read_buffer));
891 }
892 
894 {
895  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
896 
897 /* Add mutex */
898 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
899 
900  char read_buffer[RB_MAX_LEN]={0};
901 
902  snprintf(read_buffer, sizeof(read_buffer), ":So%02d*#", max);
903 
904  return (setStandardProcedure(fd, read_buffer));
905 }
906 
907 int setMaxSlewRate(int fd, int slewRate)
908 {
909  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
910 
911 /* Add mutex */
912 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
913 
914  char read_buffer[RB_MAX_LEN]={0};
915 
916  if (slewRate < 2 || slewRate > 8)
917  return -1;
918 
919  snprintf(read_buffer, sizeof(read_buffer), ":Sw%d#", slewRate);
920 
921  return (setStandardProcedure(fd, read_buffer));
922 }
923 
924 int setObjectRA(int fd, double ra)
925 {
926  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
927 
928  int h, m, s;
929  char read_buffer[22];
930 
931 /* Add mutex */
932 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
933 
934  switch (eq_format)
935  {
937  getSexComponents(ra, &h, &m, &s);
938  snprintf(read_buffer, sizeof(read_buffer), ":Sr %02d:%02d:%02d#", h, m, s);
939  break;
941  double d_s;
942  getSexComponentsIID(ra, &h, &m, &d_s);
943  snprintf(read_buffer, sizeof(read_buffer), ":Sr %02d:%02d:%05.02f#", h, m, d_s);
944  break;
946  int frac_m;
947  getSexComponents(ra, &h, &m, &s);
948  frac_m = (s / 60.0) * 10.;
949  snprintf(read_buffer, sizeof(read_buffer), ":Sr %02d:%02d.%01d#", h, m, frac_m);
950  break;
951  default:
952  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unknown controller_format <%d>", eq_format);
953  return -1;
954  }
955 
956  return (setStandardProcedure(fd, read_buffer));
957 }
958 
959 int setObjectDEC(int fd, double dec)
960 {
961  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
962 
963 /* Add mutex */
964 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
965 
966  int d, m, s;
967  char read_buffer[22];
968 
969  switch (eq_format)
970  {
972  getSexComponents(dec, &d, &m, &s);
973  /* case with negative zero */
974  if (!d && dec < 0)
975  snprintf(read_buffer, sizeof(read_buffer), ":Sd -%02d:%02d:%02d#", d, m, s);
976  else
977  snprintf(read_buffer, sizeof(read_buffer), ":Sd %+03d:%02d:%02d#", d, m, s);
978  break;
980  double d_s;
981  getSexComponentsIID(dec, &d, &m, &d_s);
982  /* case with negative zero */
983  if (!d && dec < 0)
984  snprintf(read_buffer, sizeof(read_buffer), ":Sd -%02d:%02d:%05.02f#", d, m, d_s);
985  else
986  snprintf(read_buffer, sizeof(read_buffer), ":Sd %+03d:%02d:%05.02f#", d, m, d_s);
987  break;
989  getSexComponents(dec, &d, &m, &s);
990  /* case with negative zero */
991  if (!d && dec < 0)
992  snprintf(read_buffer, sizeof(read_buffer), ":Sd -%02d*%02d#", d, m);
993  else
994  snprintf(read_buffer, sizeof(read_buffer), ":Sd %+03d*%02d#", d, m);
995  break;
996  default:
997  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unknown controller_format <%d>", eq_format);
998  return -1;
999  }
1000 
1001  return (setStandardProcedure(fd, read_buffer));
1002 }
1003 
1004 int setCommandXYZ(int fd, int x, int y, int z, const char *cmd)
1005 {
1006  char read_buffer[RB_MAX_LEN]={0};
1007 
1008  snprintf(read_buffer, sizeof(read_buffer), "%s %02d:%02d:%02d#", cmd, x, y, z);
1009 
1010 /* Add mutex */
1011 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1012 
1013  return (setStandardProcedure(fd, read_buffer));
1014 }
1015 
1016 int setAlignmentMode(int fd, unsigned int alignMode)
1017 {
1018  int error_type;
1019  int nbytes_write = 0;
1020 
1021 /* Add mutex */
1022  std::unique_lock<std::mutex> guard(lx200CommsLock);
1023 
1024  switch (alignMode)
1025  {
1026  case LX200_ALIGN_POLAR:
1027  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":AP#");
1028  if ((error_type = tty_write_string(fd, ":AP#", &nbytes_write)) != TTY_OK)
1029  return error_type;
1030  break;
1031  case LX200_ALIGN_ALTAZ:
1032  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":AA#");
1033  if ((error_type = tty_write_string(fd, ":AA#", &nbytes_write)) != TTY_OK)
1034  return error_type;
1035  break;
1036  case LX200_ALIGN_LAND:
1037  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":AL#");
1038  if ((error_type = tty_write_string(fd, ":AL#", &nbytes_write)) != TTY_OK)
1039  return error_type;
1040  break;
1041  }
1042 
1043  tcflush(fd, TCIFLUSH);
1044  return 0;
1045 }
1046 
1047 int setCalenderDate(int fd, int dd, int mm, int yy)
1048 {
1049  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1050  const struct timespec timeout = {0, 10000000L};
1051  char read_buffer[RB_MAX_LEN];
1052  char dummy_buffer[RB_MAX_LEN];
1053  int error_type;
1054  int nbytes_write = 0, nbytes_read = 0;
1055  yy = yy % 100;
1056 
1057 /* Add mutex */
1058  std::unique_lock<std::mutex> guard(lx200CommsLock);
1059 
1060  snprintf(read_buffer, sizeof(read_buffer), ":SC %02d/%02d/%02d#", mm, dd, yy);
1061 
1062  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", read_buffer);
1063 
1064  tcflush(fd, TCIFLUSH);
1065 
1066  if ((error_type = tty_write_string(fd, read_buffer, &nbytes_write)) != TTY_OK)
1067  return error_type;
1068 
1069  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
1070  // Read the next section whih has 24 blanks and then a #
1071  // Can't just use the tcflush to clear the stream because it doesn't seem to work correctly on sockets
1072  tty_nread_section(fd, dummy_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
1073 
1074  tcflush(fd, TCIFLUSH);
1075 
1076  if (nbytes_read < 1)
1077  {
1078  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response");
1079  return error_type;
1080  }
1081 
1082  read_buffer[1] = '\0';
1083 
1084  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
1085 
1086  if (read_buffer[0] == '0')
1087  return -1;
1088 
1089  /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
1090  nanosleep(&timeout, nullptr);
1091  tcflush(fd, TCIFLUSH);
1092 
1093  return 0;
1094 }
1095 
1096 int setUTCOffset(int fd, double hours)
1097 {
1098  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1099  char read_buffer[RB_MAX_LEN]={0};
1100 
1101 /* Add mutex */
1102 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1103 
1104  snprintf(read_buffer, sizeof(read_buffer), ":SG %+03d#", static_cast<int>(hours));
1105 
1106  return (setStandardProcedure(fd, read_buffer));
1107 }
1108 
1109 // Meade classic handset defines longitude as 0 to 360 WESTWARD. However,
1110 // Meade API expresses East Longitudes as negative, West Longitudes as positive.
1111 // Source: https://www.meade.com/support/LX200CommandSet.pdf from 2002 at :Gg#
1112 // (And also 10Micron has East Longitudes expressed as negative.)
1113 // Also note that this is the opposite of cartography where East is positive.
1114 int setSiteLongitude(int fd, double CartographicLongitude)
1115 {
1116  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1117  int d, m, s;
1118  char read_buffer[RB_MAX_LEN]={0};
1119  double LX200Longitude = -1.0 * CartographicLongitude;
1120 
1121 /* Add mutex */
1122 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1123  switch (geo_format) {
1124  case LX200_GEO_SHORT_FORMAT: // d m
1125  getSexComponents(LX200Longitude, &d, &m, &s);
1126  snprintf(read_buffer, sizeof(read_buffer), ":Sg%03d:%02d#", d, m);
1127  break;
1128  case LX200_GEO_LONG_FORMAT: // d m s
1129  getSexComponents(LX200Longitude, &d, &m, &s);
1130  snprintf(read_buffer, sizeof(read_buffer), ":Sg%03d:%02d:%02d#", d, m, s);
1131  break;
1132  case LX200_GEO_LONGER_FORMAT: // d m s.f with f being tenths
1133  double s_f;
1134  getSexComponentsIID(LX200Longitude, &d, &m, &s_f);
1135  snprintf(read_buffer, sizeof(read_buffer), ":Sg%03d:%02d:%04.01lf#", d, m, s_f);
1136  break;
1137  default:
1138  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unknown geographic format <%d>", geo_format);
1139  return -1;
1140  }
1141 
1142  return (setStandardProcedure(fd, read_buffer));
1143 }
1144 
1145 int setSiteLatitude(int fd, double Lat)
1146 {
1147  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1148  int d, m, s;
1149  char read_buffer[RB_MAX_LEN]={0};
1150 
1151 /* Add mutex */
1152 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1153 
1154  switch (geo_format) {
1155  case LX200_GEO_SHORT_FORMAT: // d m
1156  getSexComponents(Lat, &d, &m, &s);
1157  snprintf(read_buffer, sizeof(read_buffer), ":St%+03d:%02d#", d, m);
1158  break;
1159  case LX200_GEO_LONG_FORMAT: // d m s
1160  getSexComponents(Lat, &d, &m, &s);
1161  snprintf(read_buffer, sizeof(read_buffer), ":St%+03d:%02d:%02d#", d, m, s);
1162  break;
1163  case LX200_GEO_LONGER_FORMAT: // d m s.f with f being tenths
1164  double s_f;
1165  getSexComponentsIID(Lat, &d, &m, &s_f);
1166  snprintf(read_buffer, sizeof(read_buffer), ":St%+03d:%02d:%04.01lf#", d, m, s_f);
1167  break;
1168  default:
1169  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "Unknown geographic format <%d>", geo_format);
1170  return -1;
1171  }
1172 
1173  return (setStandardProcedure(fd, read_buffer));
1174 }
1175 
1176 int setObjAz(int fd, double az)
1177 {
1178  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1179  int d, m, s;
1180  char read_buffer[RB_MAX_LEN]={0};
1181 
1182 /* Add mutex */
1183 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1184 
1185  getSexComponents(az, &d, &m, &s);
1186 
1187  snprintf(read_buffer, sizeof(read_buffer), ":Sz%03d:%02d#", d, m);
1188 
1189  return (setStandardProcedure(fd, read_buffer));
1190 }
1191 
1192 int setObjAlt(int fd, double alt)
1193 {
1194  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1195  int d, m, s;
1196  char read_buffer[RB_MAX_LEN]={0};
1197 
1198 /* Add mutex */
1199 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1200 
1201  getSexComponents(alt, &d, &m, &s);
1202 
1203  snprintf(read_buffer, sizeof(read_buffer), ":Sa%+02d*%02d#", d, m);
1204 
1205  return (setStandardProcedure(fd, read_buffer));
1206 }
1207 
1208 int setSiteName(int fd, char *siteName, int siteNum)
1209 {
1210  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1211  char read_buffer[RB_MAX_LEN]={0};
1212 
1213 /* Add mutex */
1214 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1215 
1216  switch (siteNum)
1217  {
1218  case 1:
1219  snprintf(read_buffer, sizeof(read_buffer), ":SM %s#", siteName);
1220  break;
1221  case 2:
1222  snprintf(read_buffer, sizeof(read_buffer), ":SN %s#", siteName);
1223  break;
1224  case 3:
1225  snprintf(read_buffer, sizeof(read_buffer), ":SO %s#", siteName);
1226  break;
1227  case 4:
1228  snprintf(read_buffer, sizeof(read_buffer), ":SP %s#", siteName);
1229  break;
1230  default:
1231  return -1;
1232  }
1233 
1234  return (setStandardProcedure(fd, read_buffer));
1235 }
1236 
1237 int setSlewMode(int fd, int slewMode)
1238 {
1239  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1240  int error_type;
1241  int nbytes_write = 0;
1242 
1243 /* Add mutex */
1244  std::unique_lock<std::mutex> guard(lx200CommsLock);
1245 
1246  switch (slewMode)
1247  {
1248  case LX200_SLEW_MAX:
1249  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":RS#");
1250  if ((error_type = tty_write_string(fd, ":RS#", &nbytes_write)) != TTY_OK)
1251  return error_type;
1252  break;
1253  case LX200_SLEW_FIND:
1254  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":RM#");
1255  if ((error_type = tty_write_string(fd, ":RM#", &nbytes_write)) != TTY_OK)
1256  return error_type;
1257  break;
1258  case LX200_SLEW_CENTER:
1259  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":RC#");
1260  if ((error_type = tty_write_string(fd, ":RC#", &nbytes_write)) != TTY_OK)
1261  return error_type;
1262  break;
1263  case LX200_SLEW_GUIDE:
1264  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":RG#");
1265  if ((error_type = tty_write_string(fd, ":RG#", &nbytes_write)) != TTY_OK)
1266  return error_type;
1267  break;
1268  default:
1269  break;
1270  }
1271 
1272  tcflush(fd, TCIFLUSH);
1273  return 0;
1274 }
1275 
1276 int setFocuserMotion(int fd, int motionType)
1277 {
1278  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1279  int error_type;
1280  int nbytes_write = 0;
1281 
1282 /* Add mutex */
1283  std::unique_lock<std::mutex> guard(lx200CommsLock);
1284 
1285  switch (motionType)
1286  {
1287  case LX200_FOCUSIN:
1288  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":F+#");
1289  if ((error_type = tty_write_string(fd, ":F+#", &nbytes_write)) != TTY_OK)
1290  return error_type;
1291  break;
1292  case LX200_FOCUSOUT:
1293  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":F-#");
1294  if ((error_type = tty_write_string(fd, ":F-#", &nbytes_write)) != TTY_OK)
1295  return error_type;
1296  break;
1297  }
1298 
1299  tcflush(fd, TCIFLUSH);
1300  return 0;
1301 }
1302 
1303 int setFocuserSpeedMode(int fd, int speedMode)
1304 {
1305  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1306  int error_type;
1307  int nbytes_write = 0;
1308 
1309 /* Add mutex */
1310  std::unique_lock<std::mutex> guard(lx200CommsLock);
1311 
1312  switch (speedMode)
1313  {
1314  case LX200_HALTFOCUS:
1315  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":FQ#");
1316  if ((error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK)
1317  return error_type;
1318  break;
1319  case LX200_FOCUSSLOW:
1320  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":FS#");
1321  if ((error_type = tty_write_string(fd, ":FS#", &nbytes_write)) != TTY_OK)
1322  return error_type;
1323  break;
1324  case LX200_FOCUSFAST:
1325  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":FF#");
1326  if ((error_type = tty_write_string(fd, ":FF#", &nbytes_write)) != TTY_OK)
1327  return error_type;
1328  break;
1329  }
1330 
1331  tcflush(fd, TCIFLUSH);
1332  return 0;
1333 }
1334 
1335 int setGPSFocuserSpeed(int fd, int speed)
1336 {
1337  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1338  char speed_str[8];
1339  int error_type;
1340  int nbytes_write = 0;
1341 
1342 /* Add mutex */
1343  std::unique_lock<std::mutex> guard(lx200CommsLock);
1344 
1345  if (speed == 0)
1346  {
1347  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":FQ#");
1348  if ((error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK)
1349  return error_type;
1350 
1351  tcflush(fd, TCIFLUSH);
1352  return 0;
1353  }
1354 
1355  snprintf(speed_str, 8, ":F%d#", speed);
1356 
1357  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", speed_str);
1358 
1359  if ((error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK)
1360  return error_type;
1361 
1362  tcflush(fd, TCIFLUSH);
1363  return 0;
1364 }
1365 
1366 int setTrackFreq(int fd, double trackF)
1367 {
1368  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1369  char read_buffer[RB_MAX_LEN]={0};
1370 
1371 /* Add mutex */
1372 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1373 
1374  snprintf(read_buffer, sizeof(read_buffer), ":ST %04.1f#", trackF);
1375 
1376  return (setStandardProcedure(fd, read_buffer));
1377 }
1378 
1379 int setPreciseTrackFreq(int fd, double trackF)
1380 {
1381  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1382  char read_buffer[RB_MAX_LEN]={0};
1383 
1384  snprintf(read_buffer, sizeof(read_buffer), ":ST %08.5f#", trackF);
1385 
1386 /* Add mutex */
1387 /* std::unique_lock<std::mutex> guard(lx200CommsLock); */
1388 
1389  return (setStandardProcedure(fd, read_buffer));
1390 }
1391 
1392 /**********************************************************************
1393 * Misc
1394 *********************************************************************/
1395 
1396 int Slew(int fd)
1397 {
1398  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1399  char slewNum[2];
1400  int error_type;
1401  int nbytes_write = 0, nbytes_read = 0;
1402 
1403  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":MS#");
1404 
1405 /* Add mutex */
1406  std::unique_lock<std::mutex> guard(lx200CommsLock);
1407 
1408  if ((error_type = tty_write_string(fd, ":MS#", &nbytes_write)) != TTY_OK)
1409  return error_type;
1410 
1411  error_type = tty_read(fd, slewNum, 1, LX200_TIMEOUT, &nbytes_read);
1412 
1413  if (nbytes_read < 1)
1414  {
1415  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES ERROR <%d>", error_type);
1416  return error_type;
1417  }
1418 
1419  /* We don't need to read the string message, just return corresponding error code */
1420  tcflush(fd, TCIFLUSH);
1421 
1422  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", slewNum[0]);
1423 
1424  error_type = slewNum[0] - '0';
1425  if ((error_type >= 0) && (error_type <= 9)) {
1426  return error_type;
1427  } else {
1428  return -1;
1429  }
1430 }
1431 
1432 int MoveTo(int fd, int direction)
1433 {
1434  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1435  int nbytes_write = 0;
1436 
1437 /* Add mutex */
1438  std::unique_lock<std::mutex> guard(lx200CommsLock);
1439 
1440  switch (direction)
1441  {
1442  case LX200_NORTH:
1443  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Mn#");
1444  tty_write_string(fd, ":Mn#", &nbytes_write);
1445  break;
1446  case LX200_WEST:
1447  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Mw#");
1448  tty_write_string(fd, ":Mw#", &nbytes_write);
1449  break;
1450  case LX200_EAST:
1451  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Me#");
1452  tty_write_string(fd, ":Me#", &nbytes_write);
1453  break;
1454  case LX200_SOUTH:
1455  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Ms#");
1456  tty_write_string(fd, ":Ms#", &nbytes_write);
1457  break;
1458  default:
1459  break;
1460  }
1461 
1462  tcflush(fd, TCIFLUSH);
1463  return 0;
1464 }
1465 
1466 int SendPulseCmd(int fd, int direction, int duration_msec)
1467 {
1468  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1469  int nbytes_write = 0;
1470  char cmd[20];
1471  switch (direction)
1472  {
1473  case LX200_NORTH:
1474  sprintf(cmd, ":Mgn%04d#", duration_msec);
1475  break;
1476  case LX200_SOUTH:
1477  sprintf(cmd, ":Mgs%04d#", duration_msec);
1478  break;
1479  case LX200_EAST:
1480  sprintf(cmd, ":Mge%04d#", duration_msec);
1481  break;
1482  case LX200_WEST:
1483  sprintf(cmd, ":Mgw%04d#", duration_msec);
1484  break;
1485  default:
1486  return 1;
1487  }
1488 
1489  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd);
1490 
1491 /* Add mutex */
1492  std::unique_lock<std::mutex> guard(lx200CommsLock);
1493 
1494  tty_write_string(fd, cmd, &nbytes_write);
1495 
1496  tcflush(fd, TCIFLUSH);
1497  return 0;
1498 }
1499 
1500 int HaltMovement(int fd, int direction)
1501 {
1502  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1503  int error_type;
1504  int nbytes_write = 0;
1505 
1506 /* Add mutex */
1507  std::unique_lock<std::mutex> guard(lx200CommsLock);
1508 
1509  switch (direction)
1510  {
1511  case LX200_NORTH:
1512  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Qn#");
1513  if ((error_type = tty_write_string(fd, ":Qn#", &nbytes_write)) != TTY_OK)
1514  return error_type;
1515  break;
1516  case LX200_WEST:
1517  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Qw#");
1518  if ((error_type = tty_write_string(fd, ":Qw#", &nbytes_write)) != TTY_OK)
1519  return error_type;
1520  break;
1521  case LX200_EAST:
1522  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Qe#");
1523  if ((error_type = tty_write_string(fd, ":Qe#", &nbytes_write)) != TTY_OK)
1524  return error_type;
1525  break;
1526  case LX200_SOUTH:
1527  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Qs#");
1528  if ((error_type = tty_write_string(fd, ":Qs#", &nbytes_write)) != TTY_OK)
1529  return error_type;
1530  break;
1531  case LX200_ALL:
1532  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":Q#");
1533  if ((error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK)
1534  return error_type;
1535  break;
1536  default:
1537  return -1;
1538  }
1539 
1540  tcflush(fd, TCIFLUSH);
1541  return 0;
1542 }
1543 
1544 int abortSlew(int fd)
1545 {
1546  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1547  int error_type;
1548  int nbytes_write = 0;
1549 
1550 /* Add mutex */
1551  std::unique_lock<std::mutex> guard(lx200CommsLock);
1552 
1553 
1554  if ((error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK)
1555  return error_type;
1556 
1557  tcflush(fd, TCIFLUSH);
1558  return 0;
1559 }
1560 
1561 int Sync(int fd, char *matchedObject)
1562 {
1563  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1564  const struct timespec timeout = {0, 10000000L};
1565  int error_type;
1566  int nbytes_write = 0, nbytes_read = 0;
1567 
1568  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":CM#");
1569 /* Add mutex */
1570  std::unique_lock<std::mutex> guard(lx200CommsLock);
1571 
1572 
1573  if ((error_type = tty_write_string(fd, ":CM#", &nbytes_write)) != TTY_OK)
1574  return error_type;
1575 
1576  error_type = tty_nread_section(fd, matchedObject, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
1577 
1578  if (nbytes_read < 1)
1579  return error_type;
1580 
1581  matchedObject[nbytes_read - 1] = '\0';
1582 
1583  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", matchedObject);
1584 
1585  /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
1586  nanosleep(&timeout, nullptr);
1587  tcflush(fd, TCIFLUSH);
1588 
1589  return 0;
1590 }
1591 
1592 int selectSite(int fd, int siteNum)
1593 {
1594  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1595  int error_type;
1596  int nbytes_write = 0;
1597 
1598 /* Add mutex */
1599  std::unique_lock<std::mutex> guard(lx200CommsLock);
1600 
1601 
1602  switch (siteNum)
1603  {
1604  case 1:
1605  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":W1#");
1606  if ((error_type = tty_write_string(fd, ":W0#", &nbytes_write)) != TTY_OK) //azwing index starts at 0 not 1
1607  return error_type;
1608  break;
1609  case 2:
1610  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":W2#");
1611  if ((error_type = tty_write_string(fd, ":W1#", &nbytes_write)) != TTY_OK) //azwing index starts at 0 not 1
1612  return error_type;
1613  break;
1614  case 3:
1615  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":W3#");
1616  if ((error_type = tty_write_string(fd, ":W2#", &nbytes_write)) != TTY_OK) //azwing index starts at 0 not 1
1617  return error_type;
1618  break;
1619  case 4:
1620  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":W4#");
1621  if ((error_type = tty_write_string(fd, ":W3#", &nbytes_write)) != TTY_OK) //azwing index starts at 0 not 1
1622  return error_type;
1623  break;
1624  default:
1625  return -1;
1626  }
1627 
1628  tcflush(fd, TCIFLUSH);
1629  return 0;
1630 }
1631 
1632 int selectCatalogObject(int fd, int catalog, int NNNN)
1633 {
1634  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1635  char read_buffer[RB_MAX_LEN]={0};
1636  int error_type;
1637  int nbytes_write = 0;
1638 
1639  switch (catalog)
1640  {
1641  case LX200_STAR_C:
1642  snprintf(read_buffer, sizeof(read_buffer), ":LS%d#", NNNN);
1643  break;
1644  case LX200_DEEPSKY_C:
1645  snprintf(read_buffer, sizeof(read_buffer), ":LC%d#", NNNN);
1646  break;
1647  case LX200_MESSIER_C:
1648  snprintf(read_buffer, sizeof(read_buffer), ":LM%d#", NNNN);
1649  break;
1650  default:
1651  return -1;
1652  }
1653 
1654  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", read_buffer);
1655 
1656 /* Add mutex */
1657  std::unique_lock<std::mutex> guard(lx200CommsLock);
1658 
1659 
1660  if ((error_type = tty_write_string(fd, read_buffer, &nbytes_write)) != TTY_OK)
1661  return error_type;
1662 
1663  tcflush(fd, TCIFLUSH);
1664  return 0;
1665 }
1666 
1667 int selectSubCatalog(int fd, int catalog, int subCatalog)
1668 {
1669  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1670  char read_buffer[RB_MAX_LEN]={0};
1671  switch (catalog)
1672  {
1673  case LX200_STAR_C:
1674  snprintf(read_buffer, sizeof(read_buffer), ":LsD%d#", subCatalog);
1675  break;
1676  case LX200_DEEPSKY_C:
1677  snprintf(read_buffer, sizeof(read_buffer), ":LoD%d#", subCatalog);
1678  break;
1679  case LX200_MESSIER_C:
1680  return 1;
1681  default:
1682  return 0;
1683  }
1684 
1685  return (setStandardProcedure(fd, read_buffer));
1686 }
1687 
1689 {
1690  return eq_format;
1691 }
1692 
1694 {
1695  return geo_format;
1696 }
1697 
1699 {
1700  char read_buffer[RB_MAX_LEN] = {0};
1702  int error_type;
1703  int nbytes_write = 0, nbytes_read = 0;
1704 
1705  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GR#");
1706 
1707 /* Add mutex */
1708  std::unique_lock<std::mutex> guard(lx200CommsLock);
1709 
1710  tcflush(fd, TCIFLUSH);
1711 
1712  if ((error_type = tty_write_string(fd, ":GR#", &nbytes_write)) != TTY_OK)
1713  return error_type;
1714 
1715  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
1716 
1717  if (nbytes_read < 1)
1718  {
1719  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES ERROR <%d>", error_type);
1720  return error_type;
1721  }
1722 
1723  read_buffer[nbytes_read - 1] = '\0';
1724 
1725  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
1726 
1727  // 10micron returns on U2 15:46:18.03 . Prevent setting it to a lower precision later by detecting this mode here.
1728  if (nbytes_read >= 11 && read_buffer[8] == '.')
1729  {
1731  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Equatorial coordinate format is ultra high precision.");
1732  return 0;
1733  }
1734 
1735  /* If it's short format, try to toggle to high precision format */
1736  if (read_buffer[5] == '.')
1737  {
1738  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Detected low precision equatorial format, attempting to switch to high precision.");
1739  if ((error_type = tty_write_string(fd, ":U#", &nbytes_write)) != TTY_OK)
1740  return error_type;
1741  }
1742  else if (read_buffer[8] == '.')
1743  {
1745  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Equatorial coordinate format is ultra high precision.");
1746  return 0;
1747  }
1748  else
1749  {
1751  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Equatorial coordinate format is high precision.");
1752  return 0;
1753  }
1754 
1755  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":GR#");
1756 
1757  tcflush(fd, TCIFLUSH);
1758 
1759  if ((error_type = tty_write_string(fd, ":GR#", &nbytes_write)) != TTY_OK)
1760  return error_type;
1761 
1762  error_type = tty_nread_section(fd, read_buffer, RB_MAX_LEN, '#', LX200_TIMEOUT, &nbytes_read);
1763 
1764  if (nbytes_read < 1)
1765  {
1766  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES ERROR <%d>", error_type);
1767  return error_type;
1768  }
1769 
1770  read_buffer[nbytes_read - 1] = '\0';
1771 
1772  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", read_buffer);
1773 
1774  if (read_buffer[5] == '.')
1775  {
1777  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Equatorial coordinate format is low precision.");
1778  }
1779  else
1780  {
1782  DEBUGDEVICE(lx200Name, DBG_SCOPE, "Equatorial coordinate format is high precision.");
1783  }
1784 
1785  tcflush(fd, TCIFLUSH);
1786 
1787  return 0;
1788 }
1789 
1790 int selectTrackingMode(int fd, int trackMode)
1791 {
1792  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__);
1793  int error_type;
1794  int nbytes_write = 0;
1795 
1796 /* Add mutex */
1797  std::unique_lock<std::mutex> guard(lx200CommsLock);
1798 
1799  switch (trackMode)
1800  {
1801  case LX200_TRACK_SIDEREAL:
1802  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":TQ#");
1803  if ((error_type = tty_write_string(fd, ":TQ#", &nbytes_write)) != TTY_OK)
1804  return error_type;
1805  break;
1806  case LX200_TRACK_SOLAR:
1807  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":TS#");
1808  if ((error_type = tty_write_string(fd, ":TS#", &nbytes_write)) != TTY_OK)
1809  return error_type;
1810  break;
1811  case LX200_TRACK_LUNAR:
1812  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":TL#");
1813  if ((error_type = tty_write_string(fd, ":TL#", &nbytes_write)) != TTY_OK)
1814  return error_type;
1815  break;
1816  case LX200_TRACK_MANUAL:
1817  DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", ":TM#");
1818  if ((error_type = tty_write_string(fd, ":TM#", &nbytes_write)) != TTY_OK)
1819  return error_type;
1820  break;
1821  default:
1822  return -1;
1823  }
1824 
1825  tcflush(fd, TCIFLUSH);
1826  return 0;
1827 }
MAXINDIDEVICE
#define MAXINDIDEVICE
Definition: indiapi.h:192
setSiteLatitude
int setSiteLatitude(int fd, double Lat)
Definition: lx200driver.cpp:1145
setObjAz
int setObjAz(int fd, double az)
Definition: lx200driver.cpp:1176
setLX200Debug
void setLX200Debug(const char *deviceName, unsigned int debug_level)
Definition: lx200driver.cpp:58
setSlewMode
int setSlewMode(int fd, int slewMode)
Definition: lx200driver.cpp:1237
SendPulseCmd
int SendPulseCmd(int fd, int direction, uint32_t duration_msec)
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
LX200_ALIGN_LAND
@ LX200_ALIGN_LAND
Definition: lx200driver.h:36
fd
int fd
Definition: indiserver.c:117
lx200CommsLock
std::mutex lx200CommsLock
Definition: lx200driver.cpp:56
tty_nread_section
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:657
Aux::ANY
@ ANY
Definition: celestronauxpacket.h:86
getSiteLatitude
int getSiteLatitude(int fd, int *dd, int *mm, double *ssf)
Definition: lx200driver.cpp:539
min
double min(void)
LX200_TRACK_SOLAR
@ LX200_TRACK_SOLAR
Definition: lx200driver.h:108
indicom.h
Implementations for common driver routines.
LX200_EQ_LONGER_FORMAT
@ LX200_EQ_LONGER_FORMAT
Definition: lx200driver.h:52
LX200_FOCUSSLOW
@ LX200_FOCUSSLOW
Definition: lx200driver.h:77
getSexComponents
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:250
DBG_SCOPE
unsigned int DBG_SCOPE
Definition: lx200driver.cpp:53
f_scansexa
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:201
selectSite
int selectSite(int fd, int siteNum)
Definition: lx200driver.cpp:1592
getOTATemp
int getOTATemp(int fd, double *value)
Definition: lx200driver.cpp:779
setUTCOffset
int setUTCOffset(int fd, double hours)
Definition: lx200driver.cpp:1096
LX200_NORTH
@ LX200_NORTH
Definition: lx200driver.h:41
setSiteName
int setSiteName(int fd, char *siteName, int siteNum)
Definition: lx200driver.cpp:1208
LX200_DEEPSKY_C
@ LX200_DEEPSKY_C
Definition: lx200driver.h:84
LX200_SLEW_FIND
@ LX200_SLEW_FIND
Definition: lx200driver.h:27
geo_format
int geo_format
Definition: lx200driver.cpp:50
LX200_GEO_LONG_FORMAT
@ LX200_GEO_LONG_FORMAT
Definition: lx200driver.h:58
LX200_WEST
@ LX200_WEST
Definition: lx200driver.h:42
lx200driver.h
getSiteName
int getSiteName(int fd, char *siteName, int siteNum)
Definition: lx200driver.cpp:480
selectTrackingMode
int selectTrackingMode(int fd, int trackMode)
Definition: lx200driver.cpp:1790
selectSubCatalog
int selectSubCatalog(int fd, int catalog, int subCatalog)
Definition: lx200driver.cpp:1667
getCalendarDate
int getCalendarDate(int fd, char *date)
Definition: lx200driver.cpp:398
getSiteLatitudeAlt
int getSiteLatitudeAlt(int fd, int *dd, int *mm, double *ssf, const char *cmd)
Definition: lx200driver.cpp:555
DEBUGDEVICE
#define DEBUGDEVICE(device, priority, msg)
Definition: indilogger.h:60
setMaxElevationLimit
int setMaxElevationLimit(int fd, int max)
Definition: lx200driver.cpp:893
LX200_EAST
@ LX200_EAST
Definition: lx200driver.h:43
max
double max(void)
setObjAlt
int setObjAlt(int fd, double alt)
Definition: lx200driver.cpp:1192
INDI::Logger::DBG_DEBUG
@ DBG_DEBUG
Definition: indilogger.h:195
indilogger.h
setGPSFocuserSpeed
int setGPSFocuserSpeed(int fd, int speed)
Definition: lx200driver.cpp:1335
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
setSiteLongitude
int setSiteLongitude(int fd, double CartographicLongitude)
Definition: lx200driver.cpp:1114
LX200_ALIGN_POLAR
@ LX200_ALIGN_POLAR
Definition: lx200driver.h:34
LX200_MESSIER_C
@ LX200_MESSIER_C
Definition: lx200driver.h:102
setFocuserSpeedMode
int setFocuserSpeedMode(int fd, int speedMode)
Definition: lx200driver.cpp:1303
ra
double ra
Definition: ieqprolegacydriver.cpp:43
LX200_GEO_LONGER_FORMAT
@ LX200_GEO_LONGER_FORMAT
Definition: lx200driver.h:59
LX200_EQ_LONG_FORMAT
@ LX200_EQ_LONG_FORMAT
Definition: lx200driver.h:51
setMinElevationLimit
int setMinElevationLimit(int fd, int min)
Definition: lx200driver.cpp:883
getSiteLongitudeAlt
int getSiteLongitudeAlt(int fd, int *ddd, int *mm, double *ssf, const char *cmd)
Definition: lx200driver.cpp:629
abortSlew
int abortSlew(int fd)
Definition: lx200driver.cpp:1544
eq_format
int eq_format
Definition: lx200driver.cpp:49
getLX200EquatorialFormat
int getLX200EquatorialFormat()
Definition: lx200driver.cpp:1688
dec
double dec
Definition: ieqprolegacydriver.cpp:44
setStandardProcedure
int setStandardProcedure(int fd, const char *writeData)
Definition: lx200driver.cpp:821
setObjectRA
int setObjectRA(int fd, double ra)
Definition: lx200driver.cpp:924
LX200_TRACK_LUNAR
@ LX200_TRACK_LUNAR
Definition: lx200driver.h:109
LX200_GEO_SHORT_FORMAT
@ LX200_GEO_SHORT_FORMAT
Definition: lx200driver.h:57
LX200_FOCUSOUT
@ LX200_FOCUSOUT
Definition: lx200driver.h:72
setMaxSlewRate
int setMaxSlewRate(int fd, int slewRate)
Definition: lx200driver.cpp:907
getTrackFreq
int getTrackFreq(int fd, double *value)
Definition: lx200driver.cpp:703
getCommandInt
int getCommandInt(int fd, int *value, const char *cmd)
Definition: lx200driver.cpp:278
LX200_HALTFOCUS
@ LX200_HALTFOCUS
Definition: lx200driver.h:76
LX200_ALL
@ LX200_ALL
Definition: lx200driver.h:45
getHomeSearchStatus
int getHomeSearchStatus(int fd, int *status)
Definition: lx200driver.cpp:742
getSiteLongitude
int getSiteLongitude(int fd, int *ddd, int *mm, double *ssf)
Definition: lx200driver.cpp:549
isSlewComplete
int isSlewComplete(int fd)
Definition: lx200driver.cpp:350
selectCatalogObject
int selectCatalogObject(int fd, int catalog, int NNNN)
Definition: lx200driver.cpp:1632
LX200_ALIGN_ALTAZ
@ LX200_ALIGN_ALTAZ
Definition: lx200driver.h:35
ACK
char ACK(int fd)
Definition: lx200driver.cpp:213
Sync
int Sync(int fd, char *matchedObject)
Definition: lx200driver.cpp:1561
setCalenderDate
int setCalenderDate(int fd, int dd, int mm, int yy)
Definition: lx200driver.cpp:1047
setCommandInt
int setCommandInt(int fd, int data, const char *cmd)
Definition: lx200driver.cpp:855
lx200Name
char lx200Name[MAXINDIDEVICE]
Definition: lx200driver.cpp:51
LX200_STAR_C
@ LX200_STAR_C
Definition: lx200driver.h:83
setAlignmentMode
int setAlignmentMode(int fd, unsigned int alignMode)
Definition: lx200driver.cpp:1016
setPreciseTrackFreq
int setPreciseTrackFreq(int fd, double trackF)
Definition: lx200driver.cpp:1379
DEBUGFDEVICE
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
LX200_EQ_SHORT_FORMAT
@ LX200_EQ_SHORT_FORMAT
Definition: lx200driver.h:50
LX200_TRACK_MANUAL
@ LX200_TRACK_MANUAL
Definition: lx200driver.h:110
LX200_SLEW_GUIDE
@ LX200_SLEW_GUIDE
Definition: lx200driver.h:29
RB_MAX_LEN
#define RB_MAX_LEN
Definition: lx200driver.cpp:46
setTrackFreq
int setTrackFreq(int fd, double trackF)
Definition: lx200driver.cpp:1366
LX200_FOCUSIN
@ LX200_FOCUSIN
Definition: lx200driver.h:71
setFocuserMotion
int setFocuserMotion(int fd, int motionType)
Definition: lx200driver.cpp:1276
LX200_TRACK_SIDEREAL
@ LX200_TRACK_SIDEREAL
Definition: lx200driver.h:107
setObjectDEC
int setObjectDEC(int fd, double dec)
Definition: lx200driver.cpp:959
LX200_SLEW_MAX
@ LX200_SLEW_MAX
Definition: lx200driver.h:26
LX200_SOUTH
@ LX200_SOUTH
Definition: lx200driver.h:44
getCommandString
int getCommandString(int fd, char *data, const char *cmd)
Definition: lx200driver.cpp:321
checkLX200EquatorialFormat
int checkLX200EquatorialFormat(int fd)
Definition: lx200driver.cpp:1698
getTimeFormat
int getTimeFormat(int fd, int *format)
Definition: lx200driver.cpp:438
LX200_TIMEOUT
#define LX200_TIMEOUT
Definition: lx200driver.cpp:45
getSexComponentsIID
void getSexComponentsIID(double value, int *d, int *m, double *s)
Definition: indicom.c:273
LX200_SLEW_CENTER
@ LX200_SLEW_CENTER
Definition: lx200driver.h:28
Slew
int Slew(int fd)
Definition: lx200driver.cpp:1396
MoveTo
int MoveTo(int fd, int direction)
Definition: lx200driver.cpp:1432
tty_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:465
TTY_OK
@ TTY_OK
Definition: indicom.h:94
check_lx200_connection
int check_lx200_connection(int fd)
Definition: lx200driver.cpp:176
LX200_FOCUSFAST
@ LX200_FOCUSFAST
Definition: lx200driver.h:78
HaltMovement
int HaltMovement(int fd, int direction)
Definition: lx200driver.cpp:1500
getLX200GeographicFormat
int getLX200GeographicFormat()
Definition: lx200driver.cpp:1693
setCommandXYZ
int setCommandXYZ(int fd, int x, int y, int z, const char *cmd)
Definition: lx200driver.cpp:1004
getCommandSexa
int getCommandSexa(int fd, double *value, const char *cmd)
Definition: lx200driver.cpp:241