1 #if 0
2 LX200 Astro - Physics Driver
3 Copyright (C) 2007 Markus Wildi
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 <cmath>
26 #include "lx200apdriver.h"
27 
28 #include "indicom.h"
29 #include "indilogger.h"
30 #include "lx200driver.h"
31 
32 #include <cstring>
33 #include <unistd.h>
34 
35 #ifndef _WIN32
36 #include <termios.h>
37 #endif
38 
39 #define LX200_TIMEOUT 5 /* FD timeout in seconds */
40 
41 // maximum guide pulse request to send to controller
42 #define MAX_LX200AP_PULSE_LEN 999
43 
44 char lx200ap_name[MAXINDIDEVICE];
45 unsigned int AP_DBG_SCOPE;
46 
set_lx200ap_name(const char * deviceName,unsigned int debug_level)47 void set_lx200ap_name(const char *deviceName, unsigned int debug_level)
48 {
49     strncpy(lx200ap_name, deviceName, MAXINDIDEVICE);
50     AP_DBG_SCOPE = debug_level;
51 }
52 
check_lx200ap_connection(int fd)53 int check_lx200ap_connection(int fd)
54 {
55     const struct timespec timeout = {0, 50000000L};
56     int i = 0;
57     char temp_string[64];
58     int error_type;
59     int nbytes_write = 0;
60     int nbytes_read  = 0;
61 
62     DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "Testing telescope's connection using #:GG#...");
63 
64     if (fd <= 0)
65     {
66         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR,
67                     "check_lx200ap_connection: not a valid file descriptor received");
68 
69         return -1;
70     }
71     for (i = 0; i < 2; i++)
72     {
73         if ((error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK)
74         {
75             DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR,
76                          "check_lx200ap_connection: unsuccessful write to telescope, %d", nbytes_write);
77 
78             return error_type;
79         }
80         tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
81         tcflush(fd, TCIFLUSH);
82         if (nbytes_read > 1)
83         {
84             temp_string[nbytes_read - 1] = '\0';
85 
86             DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: received bytes %d, [%s]",
87                          nbytes_write, temp_string);
88 
89             return 0;
90         }
91         nanosleep(&timeout, nullptr);
92     }
93 
94     DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: wrote, but nothing received.");
95 
96     return -1;
97 }
getAPUTCOffset(int fd,double * value)98 int getAPUTCOffset(int fd, double *value)
99 {
100     int error_type;
101     int nbytes_write = 0;
102     int nbytes_read  = 0;
103 
104     char temp_string[16];
105 
106     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:GG#");
107 
108     if ((error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK)
109         return error_type;
110 
111     if ((error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
112     {
113         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: saying good bye %d, %d", error_type,
114                      nbytes_read);
115         return error_type;
116     }
117 
118     tcflush(fd, TCIFLUSH);
119 
120     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES <%s>", temp_string);
121 
122     /* Negative offsets, see AP keypad manual p. 77 */
123     if ((temp_string[0] == 'A') || ((temp_string[0] == '0') && (temp_string[1] == '0')) || (temp_string[0] == '@'))
124     {
125         int i;
126         for (i = nbytes_read; i > 0; i--)
127         {
128             temp_string[i] = temp_string[i - 1];
129         }
130         temp_string[0]               = '-';
131         temp_string[nbytes_read + 1] = '\0';
132 
133         if (temp_string[1] == 'A')
134         {
135             temp_string[1] = '0';
136             switch (temp_string[2])
137             {
138             case '5':
139 
140                 temp_string[2] = '1';
141                 break;
142             case '4':
143 
144                 temp_string[2] = '2';
145                 break;
146             case '3':
147 
148                 temp_string[2] = '3';
149                 break;
150             case '2':
151 
152                 temp_string[2] = '4';
153                 break;
154             case '1':
155 
156                 temp_string[2] = '5';
157                 break;
158             default:
159                 DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s",
160                              temp_string);
161                 return -1;
162                 break;
163             }
164         }
165         else if (temp_string[1] == '0')
166         {
167             temp_string[1] = '0';
168             temp_string[2] = '6';
169         }
170         else if (temp_string[1] == '@')
171         {
172             temp_string[1] = '0';
173             switch (temp_string[2])
174             {
175             case '9':
176 
177                 temp_string[2] = '7';
178                 break;
179             case '8':
180 
181                 temp_string[2] = '8';
182                 break;
183             case '7':
184 
185                 temp_string[2] = '9';
186                 break;
187             case '6':
188 
189                 temp_string[2] = '0';
190                 break;
191             case '5':
192                 temp_string[1] = '1';
193                 temp_string[2] = '1';
194                 break;
195             case '4':
196 
197                 temp_string[1] = '1';
198                 temp_string[2] = '2';
199                 break;
200             default:
201                 DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s",
202                              temp_string);
203                 return -1;
204                 break;
205             }
206         }
207         else
208         {
209             DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s", temp_string);
210         }
211     }
212     else
213     {
214         temp_string[nbytes_read - 1] = '\0';
215     }
216 
217     if (f_scansexa(temp_string, value))
218     {
219         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: unable to process %s", temp_string);
220         return -1;
221     }
222     return 0;
223 }
224 
setAPObjectAZ(int fd,double az)225 int setAPObjectAZ(int fd, double az)
226 {
227     int h, m, s;
228     char temp_string[16];
229 
230     getSexComponents(az, &h, &m, &s);
231 
232     snprintf(temp_string, sizeof(temp_string), "#:Sz %03d*%02d:%02d#", h, m, s);
233 
234     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
235 
236     return (setStandardProcedure(fd, temp_string));
237 }
238 
239 /* wildi Valid set Values are positive, add error condition */
240 
setAPObjectAlt(int fd,double alt)241 int setAPObjectAlt(int fd, double alt)
242 {
243     int d, m, s;
244     char temp_string[16];
245 
246     getSexComponents(alt, &d, &m, &s);
247 
248     /* case with negative zero */
249     if (!d && alt < 0)
250     {
251         snprintf(temp_string, sizeof(temp_string), "#:Sa -%02d*%02d:%02d#", d, m, s);
252     }
253     else
254     {
255         snprintf(temp_string, sizeof(temp_string), "#:Sa %+02d*%02d:%02d#", d, m, s);
256     }
257 
258     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
259 
260     return (setStandardProcedure(fd, temp_string));
261 }
setAPUTCOffset(int fd,double hours)262 int setAPUTCOffset(int fd, double hours)
263 {
264     int h, m, s;
265 
266     char temp_string[16];
267 
268     getSexComponents(hours, &h, &m, &s);
269 
270     snprintf(temp_string, sizeof(temp_string), "#:SG %+03d:%02d:%02d#", h, m, s);
271 
272     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
273 
274     return (setStandardProcedure(fd, temp_string));
275 }
APSyncCM(int fd,char * matchedObject)276 int APSyncCM(int fd, char *matchedObject)
277 {
278     const struct timespec timeout = {0, 10000000L};
279     int error_type;
280     int nbytes_write = 0;
281     int nbytes_read  = 0;
282 
283     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:CM#");
284 
285     if ((error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK)
286         return error_type;
287 
288     if ((error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
289         return error_type;
290 
291     matchedObject[nbytes_read - 1] = '\0';
292 
293     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES <%s>", matchedObject);
294 
295     /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
296     nanosleep(&timeout, nullptr);
297 
298     tcflush(fd, TCIFLUSH);
299 
300     return 0;
301 }
302 
APSyncCMR(int fd,char * matchedObject)303 int APSyncCMR(int fd, char *matchedObject)
304 {
305     const struct timespec timeout = {0, 10000000L};
306     int error_type;
307     int nbytes_write = 0;
308     int nbytes_read  = 0;
309 
310     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:CMR#");
311 
312     if ((error_type = tty_write_string(fd, "#:CMR#", &nbytes_write)) != TTY_OK)
313         return error_type;
314 
315     /* read_ret = portRead(matchedObject, -1, LX200_TIMEOUT); */
316     if ((error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
317         return error_type;
318 
319     matchedObject[nbytes_read - 1] = '\0';
320 
321     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES <%s>", matchedObject);
322 
323     /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
324     nanosleep(&timeout, nullptr);
325 
326     tcflush(fd, TCIFLUSH);
327 
328     return 0;
329 }
330 
selectAPPECState(int fd,int pecstate)331 int selectAPPECState(int fd, int pecstate)
332 {
333     int error_type;
334     int nbytes_write = 0;
335 
336     switch (pecstate)
337     {
338     // PEC OFF
339     case 0:
340         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPPECState: Setting PEC OFF");
341         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:p#");
342 
343         if ((error_type = tty_write_string(fd, "#:p#", &nbytes_write)) != TTY_OK)
344             return error_type;
345 
346         break;
347 
348         // PEC ON
349     case 1:
350         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPPECState: Setting PEC ON");
351         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:pP#");
352 
353         if ((error_type = tty_write_string(fd, "#:pP#", &nbytes_write)) != TTY_OK)
354             return error_type;
355 
356         break;
357 
358     default:
359         return -1;
360         break;
361     }
362 
363     return 0;
364 }
365 
selectAPMoveToRate(int fd,int moveToRate)366 int selectAPMoveToRate(int fd, int moveToRate)
367 {
368     int error_type;
369     int nbytes_write = 0;
370 
371     switch (moveToRate)
372     {
373     /* 12x*/
374     case 0:
375         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 12x");
376         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RC0#");
377 
378         if ((error_type = tty_write_string(fd, "#:RC0#", &nbytes_write)) != TTY_OK)
379             return error_type;
380         break;
381 
382     /* 64x */
383     case 1:
384         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 64x");
385         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RC1#");
386 
387         if ((error_type = tty_write_string(fd, "#:RC1#", &nbytes_write)) != TTY_OK)
388             return error_type;
389         break;
390 
391     /* 600x */
392     case 2:
393         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 600x");
394         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RC2#");
395         if ((error_type = tty_write_string(fd, "#:RC2#", &nbytes_write)) != TTY_OK)
396             return error_type;
397         break;
398 
399     /* 1200x */
400     case 3:
401         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 1200x");
402         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RC3#");
403 
404         if ((error_type = tty_write_string(fd, "#:RC3#", &nbytes_write)) != TTY_OK)
405             return error_type;
406         break;
407 
408     default:
409         return -1;
410         break;
411     }
412     return 0;
413 }
414 
selectAPSlewRate(int fd,int slewRate)415 int selectAPSlewRate(int fd, int slewRate)
416 {
417     int error_type;
418     int nbytes_write = 0;
419     switch (slewRate)
420     {
421     /* 600x */
422     case 0:
423 
424         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 600x");
425         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RS0#");
426 
427         if ((error_type = tty_write_string(fd, "#:RS0#", &nbytes_write)) != TTY_OK)
428             return error_type;
429         break;
430 
431     /* 900x */
432     case 1:
433 
434         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 900x");
435         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RS1#");
436 
437         if ((error_type = tty_write_string(fd, "#:RS1#", &nbytes_write)) != TTY_OK)
438             return error_type;
439         break;
440 
441 
442     /* 1200x */
443     case 2:
444 
445         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 1200x");
446         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RS2#");
447 
448         if ((error_type = tty_write_string(fd, "#:RS2#", &nbytes_write)) != TTY_OK)
449             return error_type;
450         break;
451 
452     default:
453         return -1;
454         break;
455     }
456     return 0;
457 }
458 
selectAPTrackingMode(int fd,int trackMode)459 int selectAPTrackingMode(int fd, int trackMode)
460 {
461     int error_type;
462     int nbytes_write = 0;
463 
464     switch (trackMode)
465     {
466     /* Sidereal */
467     case AP_TRACKING_SIDEREAL:
468 
469         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG,
470                     "selectAPTrackingMode: Setting tracking mode to sidereal.");
471         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RT2#");
472 
473         if ((error_type = tty_write_string(fd, "#:RT2#", &nbytes_write)) != TTY_OK)
474             return error_type;
475         break;
476 
477         /* Solar */
478     case AP_TRACKING_SOLAR:
479 
480         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to solar.");
481         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RT1#");
482 
483         if ((error_type = tty_write_string(fd, "#:RT1#", &nbytes_write)) != TTY_OK)
484             return error_type;
485         break;
486 
487         /* Lunar */
488     case AP_TRACKING_LUNAR:
489 
490         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to lunar.");
491         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RT0#");
492 
493         if ((error_type = tty_write_string(fd, "#:RT0#", &nbytes_write)) != TTY_OK)
494             return error_type;
495         break;
496 
497     case AP_TRACKING_CUSTOM:
498             DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to Custom.");
499             break;
500 
501         /* Zero */
502     case AP_TRACKING_OFF:
503 
504         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to Zero.");
505         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RT9#");
506 
507         if ((error_type = tty_write_string(fd, "#:RT9#", &nbytes_write)) != TTY_OK)
508             return error_type;
509         break;
510 
511     default:
512         return -1;
513         break;
514     }
515     return 0;
516 }
517 
selectAPGuideRate(int fd,int guideRate)518 int selectAPGuideRate(int fd, int guideRate)
519 {
520     int error_type;
521     int nbytes_write = 0;
522     switch (guideRate)
523     {
524     /* 0.25x */
525     case 0:
526 
527         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPGuideRate: Setting guide to rate to 0.25x");
528         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RG0#");
529 
530         if ((error_type = tty_write_string(fd, "#:RG0#", &nbytes_write)) != TTY_OK)
531             return error_type;
532         break;
533 
534     /* 0.50x */
535     case 1:
536 
537         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPGuideRate: Setting guide to rate to 0.50x");
538         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RG1#");
539 
540         if ((error_type = tty_write_string(fd, "#:RG1#", &nbytes_write)) != TTY_OK)
541             return error_type;
542         break;
543 
544 
545     /* 1.00x */
546     case 2:
547 
548         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPGuideRate: Setting guide to rate to 1.00x");
549         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:RG2#");
550 
551         if ((error_type = tty_write_string(fd, "#:RG2#", &nbytes_write)) != TTY_OK)
552             return error_type;
553         break;
554 
555     default:
556         return -1;
557         break;
558     }
559     return 0;
560 }
561 
swapAPButtons(int fd,int currentSwap)562 int swapAPButtons(int fd, int currentSwap)
563 {
564     int error_type;
565     int nbytes_write = 0;
566 
567     switch (currentSwap)
568     {
569     case 0:
570 
571         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:NS#");
572         if ((error_type = tty_write_string(fd, "#:NS#", &nbytes_write)) != TTY_OK)
573             return error_type;
574         break;
575 
576     case 1:
577         DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", "#:EW#");
578         if ((error_type = tty_write_string(fd, "#:EW#", &nbytes_write)) != TTY_OK)
579             return error_type;
580         break;
581 
582     default:
583         return -1;
584         break;
585     }
586     return 0;
587 }
588 
setAPObjectRA(int fd,double ra)589 int setAPObjectRA(int fd, double ra)
590 {
591     /*ToDo AP accepts "#:Sr %02d:%02d:%02d.%1d#"*/
592     int h, m, s;
593     char temp_string[16];
594 
595     getSexComponents(ra, &h, &m, &s);
596 
597     snprintf(temp_string, sizeof(temp_string), "#:Sr %02d:%02d:%02d#", h, m, s);
598 
599     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
600 
601     return (setStandardProcedure(fd, temp_string));
602 }
603 
setAPObjectDEC(int fd,double dec)604 int setAPObjectDEC(int fd, double dec)
605 {
606     int d, m, s;
607     char temp_string[16];
608 
609     getSexComponents(dec, &d, &m, &s);
610     /* case with negative zero */
611     if (!d && dec < 0)
612     {
613         snprintf(temp_string, sizeof(temp_string), "#:Sd -%02d*%02d:%02d#", d, m, s);
614     }
615     else
616     {
617         snprintf(temp_string, sizeof(temp_string), "#:Sd %+03d*%02d:%02d#", d, m, s);
618     }
619 
620     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
621 
622     return (setStandardProcedure(fd, temp_string));
623 }
624 
setAPSiteLongitude(int fd,double Long)625 int setAPSiteLongitude(int fd, double Long)
626 {
627     int d, m, s;
628     char temp_string[32];
629 
630     getSexComponents(Long, &d, &m, &s);
631     snprintf(temp_string, sizeof(temp_string), "#:Sg %03d*%02d:%02d#", d, m, s);
632 
633     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
634 
635     return (setStandardProcedure(fd, temp_string));
636 }
637 
setAPSiteLatitude(int fd,double Lat)638 int setAPSiteLatitude(int fd, double Lat)
639 {
640     int d, m, s;
641     char temp_string[32];
642 
643     getSexComponents(Lat, &d, &m, &s);
644     snprintf(temp_string, sizeof(temp_string), "#:St %+03d*%02d:%02d#", d, m, s);
645 
646     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", temp_string);
647 
648     return (setStandardProcedure(fd, temp_string));
649 }
650 
setAPRATrackRate(int fd,double rate)651 int setAPRATrackRate(int fd, double rate)
652 {
653     char cmd[16];
654     char sign;
655     int errcode = 0;
656     char errmsg[MAXRBUF];
657     char response[8];
658     int nbytes_read    = 0;
659     int nbytes_written = 0;
660 
661     if (rate < 0)
662         sign = '-';
663     else
664         sign = '+';
665 
666     snprintf(cmd, 16, ":RR%c%03.4f#", sign, fabs(rate));
667 
668     DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd);
669 
670     tcflush(fd, TCIFLUSH);
671 
672     if ((errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
673     {
674         tty_error_msg(errcode, errmsg, MAXRBUF);
675         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "%s", errmsg);
676         return errcode;
677     }
678 
679     if ((errcode = tty_read(fd, response, 1, LX200_TIMEOUT, &nbytes_read)))
680     {
681         tty_error_msg(errcode, errmsg, MAXRBUF);
682         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "%s", errmsg);
683         return errcode;
684     }
685 
686     if (nbytes_read > 0)
687     {
688         response[nbytes_read] = '\0';
689         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "RES (%s)", response);
690 
691         tcflush(fd, TCIFLUSH);
692         return 0;
693     }
694 
695     DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read);
696     return -1;
697 }
698 
setAPDETrackRate(int fd,double rate)699 int setAPDETrackRate(int fd, double rate)
700 {
701     char cmd[16];
702     char sign;
703     int errcode = 0;
704     char errmsg[MAXRBUF];
705     char response[8];
706     int nbytes_read    = 0;
707     int nbytes_written = 0;
708 
709     if (rate < 0)
710         sign = '-';
711     else
712         sign = '+';
713 
714     snprintf(cmd, 16, ":RD%c%03.4f#", sign, fabs(rate));
715 
716     DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd);
717 
718 
719     tcflush(fd, TCIFLUSH);
720 
721     if ((errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
722     {
723         tty_error_msg(errcode, errmsg, MAXRBUF);
724         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "%s", errmsg);
725         return errcode;
726     }
727 
728     if ((errcode = tty_read(fd, response, 1, LX200_TIMEOUT, &nbytes_read)))
729     {
730         tty_error_msg(errcode, errmsg, MAXRBUF);
731         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "%s", errmsg);
732         return errcode;
733     }
734 
735     if (nbytes_read > 0)
736     {
737         response[nbytes_read] = '\0';
738         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "RES (%s)", response);
739 
740         tcflush(fd, TCIFLUSH);
741         return 0;
742     }
743 
744     DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read);
745     return -1;
746 }
747 
APSendPulseCmd(int fd,int direction,int duration_msec)748 int APSendPulseCmd(int fd, int direction, int duration_msec)
749 {
750     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "<%s>", __FUNCTION__);
751     int nbytes_write = 0;
752     char cmd[20];
753 
754     // GTOCP3 supports 3 digits for msec duration
755     if (duration_msec > MAX_LX200AP_PULSE_LEN)
756     {
757         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "APSendPulseCmd requested %d msec limited to 999 msec!", duration_msec);
758         duration_msec = 999;
759     }
760 
761     switch (direction)
762     {
763         case LX200_NORTH:
764             sprintf(cmd, ":Mn%03d#", duration_msec);
765             break;
766         case LX200_SOUTH:
767             sprintf(cmd, ":Ms%03d#", duration_msec);
768         break;
769         case LX200_EAST:
770             sprintf(cmd, ":Me%03d#", duration_msec);
771         break;
772         case LX200_WEST:
773             sprintf(cmd, ":Mw%03d#", duration_msec);
774         break;
775         default:
776             return 1;
777     }
778 
779     DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD <%s>", cmd);
780 
781     tty_write_string(fd, cmd, &nbytes_write);
782 
783     tcflush(fd, TCIFLUSH);
784     return 0;
785 }
786 
787 #if 0
788 // experimental function!!!
789 int check_lx200ap_status(int fd, char *parkStatus, char *slewStatus)
790 {
791     char temp_string[64];
792     int error_type;
793     int nbytes_write = 0;
794     int nbytes_read  = 0;
795 
796     DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "EXPERIMENTAL: check status...");
797 
798     if (fd <= 0)
799     {
800         DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR,
801                     "check_lx200ap_connection: not a valid file descriptor received");
802 
803         return -1;
804     }
805 
806     if ((error_type = tty_write_string(fd, "#:GOS#", &nbytes_write)) != TTY_OK)
807     {
808         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR,
809                      "check_lx200ap_connection: unsuccessful write to telescope, %d", nbytes_write);
810 
811         return error_type;
812     }
813     tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
814     tcflush(fd, TCIFLUSH);
815     if (nbytes_read > 1)
816     {
817         temp_string[nbytes_read - 1] = '\0';
818 
819         DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "check_lx200ap_status: received bytes %d, [%s]",
820                      nbytes_write, temp_string);
821 
822         *parkStatus = temp_string[0];
823         *slewStatus = temp_string[3];
824 
825         return 0;
826     }
827 
828 
829     DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_status: wrote, but nothing received.");
830 
831     return -1;
832 }
833 #endif
834