source: BAORadio/libindi/v1/drivers/telescope/celestronprotocol.c@ 689

Last change on this file since 689 was 490, checked in by campagne, 15 years ago

import libindi (JEC)

File size: 16.9 KB
Line 
1/*
2 * Telescope Control Protocol for Celestron NexStar GPS telescopes
3 *
4 * Copyright 2003 John Kielkopf
5 * John Kielkopf (kielkopf@louisville.edu)
6 *
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; 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; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * 15 May 2003 -- Version 2.00
22 *
23 *
24 *
25 */
26
27
28#include <stdio.h>
29#include <errno.h>
30#include <time.h>
31#include <string.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <unistd.h>
35#include <sys/stat.h>
36#include <sys/ioctl.h>
37#include <fcntl.h>
38
39/* do NOT change this to config-kstars.h!
40INDI is independent of KStars*/
41#ifdef HAVE_CONFIG_H
42#include <config.h>
43#endif
44
45#ifndef _WIN32
46#include <termios.h>
47#endif
48
49
50#include <math.h>
51#include "celestronprotocol.h"
52
53#define NULL_PTR(x) (x *)0
54
55/* There are two classes of routines defined here: */
56
57/* XmTel commands to allow easy NexStar access. These */
58/* include routines that mimic the extensive LX200 command */
59/* language and, for the most part, trap calls and */
60/* respond with an error message to the console. */
61
62/* NexStar specific commands and data. */
63
64/* The NexStar command set as documented by Celestron */
65/* is very limited. This version of xmtel uses ta few */
66/* auxilliary commands which permit direct access to the motor */
67/* controllers. */
68
69
70/* XmTel compatibility commands */
71
72int ConnectTel(char *port);
73void DisconnectTel(void);
74int CheckConnectTel(void);
75
76void SetRate(int newRate);
77void SetLimits(double limitLower, double limitHigher);
78void StartSlew(int direction);
79void StopSlew(int direction);
80double GetRA(void);
81double GetDec(void);
82int SlewToCoords(double newRA, double newDec);
83int SyncToCoords(double newRA, double newDec);
84int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC);
85
86void StopNSEW(void);
87int SetSlewRate(void);
88
89int SyncLST(double newTime);
90int SyncLocalTime(void);
91
92void Reticle(int reticle);
93void Focus(int focus);
94void Derotator(int rotate);
95void Fan(int fan);
96
97static int TelPortFD;
98static int TelConnectFlag = 0;
99
100
101/* NexStar local data */
102
103static double returnRA; /* Last update of RA */
104static double returnDec; /* Last update of Dec */
105static int updateRA; /* Set if no RA inquiry since last update */
106static int updateDec; /* Set if no Dec inquiry since last update */
107static int slewRate; /* Rate for slew request in StartSlew */
108
109
110/* Coordinate reported by NexStar = true coordinate + offset. */
111
112static double offsetRA = 0; /* Correction to RA from NexStar */
113static double offsetDec = 0; /* Correction to Dec from NexStar */
114
115
116/* NexStar local commands */
117
118void GetRAandDec(void); /* Update RA and Dec from NexStar */
119
120
121/* Serial communication utilities */
122
123
124typedef fd_set telfds;
125
126static int readn(int fd, char *ptr, int nbytes, int sec);
127static int writen(int fd, char *ptr, int nbytes);
128static int telstat(int fd,int sec,int usec);
129
130
131int CheckConnectTel(void)
132{
133 return TelConnectFlag;
134}
135
136
137
138int ConnectTel(char *port)
139{
140#ifdef _WIN32
141 return -1;
142#else
143 struct termios tty;
144 char returnStr[128];
145 int numRead;
146
147 fprintf(stderr, "Connecting to port: %s\n",port);
148
149 if(TelConnectFlag != 0)
150 return 0;
151
152 /* Make the connection */
153
154 TelPortFD = open(port,O_RDWR);
155 if(TelPortFD == -1)
156 return -1;
157
158 tcgetattr(TelPortFD,&tty);
159 cfsetospeed(&tty, (speed_t) B9600);
160 cfsetispeed(&tty, (speed_t) B9600);
161 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
162 tty.c_iflag = IGNBRK;
163 tty.c_lflag = 0;
164 tty.c_oflag = 0;
165 tty.c_cflag |= CLOCAL | CREAD;
166 tty.c_cc[VMIN] = 1;
167 tty.c_cc[VTIME] = 5;
168 tty.c_iflag &= ~(IXON|IXOFF|IXANY);
169 tty.c_cflag &= ~(PARENB | PARODD);
170 tcsetattr(TelPortFD, TCSANOW, &tty);
171
172 /* Flush the input (read) buffer */
173
174 tcflush(TelPortFD,TCIOFLUSH);
175
176 /* Test connection */
177
178 writen(TelPortFD,"Kx",2);
179 numRead=readn(TelPortFD,returnStr,3,2);
180 returnStr[numRead] = '\0';
181
182 /* Diagnostic tests */
183
184 fprintf(stderr, "ConnectTel read %d characters: %s\n",numRead,returnStr);
185 fprintf(stderr, "TelConnectFlag set to: %d\n",TelConnectFlag);
186
187 if (numRead == 2)
188 {
189 TelConnectFlag = 1;
190 return (0);
191 }
192 else
193 return -1;
194
195#endif
196}
197
198/* Assign and save slewRate for use in StartSlew */
199
200void SetRate(int newRate)
201{
202 if(newRate == SLEW)
203 {
204 slewRate = 9;
205 }
206 else if(newRate == FIND)
207 {
208 slewRate = 6;
209 }
210 else if(newRate == CENTER)
211 {
212 slewRate = 3;
213 }
214 else if(newRate == GUIDE)
215 {
216 slewRate = 1;
217 }
218
219}
220
221
222/* Start a slew in chosen direction at slewRate */
223/* Use auxilliary NexStar command set through the hand control computer */
224
225void StartSlew(int direction)
226{
227 char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x09, 0x00, 0x00, 0x00 };
228 char inputStr[2048];
229
230 if(direction == NORTH)
231 {
232 slewCmd[2] = 0x11;
233 slewCmd[3] = 0x24;
234 slewCmd[4] = slewRate;
235 }
236 else if(direction == EAST)
237 {
238 slewCmd[2] = 0x10;
239 slewCmd[3] = 0x25;
240 slewCmd[4] = slewRate;
241 }
242 else if(direction == SOUTH)
243 {
244 slewCmd[2] = 0x11;
245 slewCmd[3] = 0x25;
246 slewCmd[4] = slewRate;
247 }
248 else if(direction == WEST)
249 {
250 slewCmd[2] = 0x10;
251 slewCmd[3] = 0x24;
252 slewCmd[4] = slewRate;
253 }
254
255 writen(TelPortFD,slewCmd,8);
256
257 /* Look for '#' acknowledgment of request*/
258
259 for (;;)
260 {
261 if ( readn(TelPortFD,inputStr,1,1) )
262 {
263 if (inputStr[0] == '#') break;
264 }
265 else
266 {
267 fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n");
268 }
269 }
270}
271
272
273/* Stop the slew in chosen direction */
274
275void StopSlew(int direction)
276{
277 char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x00, 0x00, 0x00, 0x00 };
278 char inputStr[2048];
279
280 if(direction == NORTH)
281 {
282 slewCmd[2] = 0x11;
283 slewCmd[3] = 0x24;
284 }
285 else if(direction == EAST)
286 {
287 slewCmd[2] = 0x10;
288 slewCmd[3] = 0x24;
289 }
290 else if(direction == SOUTH)
291 {
292 slewCmd[2] = 0x11;
293 slewCmd[3] = 0x24;
294 }
295 else if(direction == WEST)
296 {
297 slewCmd[2] = 0x10;
298 slewCmd[3] = 0x24;
299 }
300
301 writen(TelPortFD,slewCmd,8);
302
303 /* Look for '#' acknowledgment of request*/
304
305 for (;;)
306 {
307 if ( readn(TelPortFD,inputStr,1,1) )
308 {
309 if (inputStr[0] == '#') break;
310 }
311 else
312 {
313 fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n");
314 }
315 }
316}
317
318void DisconnectTel(void)
319{
320 /* printf("DisconnectTel\n"); */
321 if(TelConnectFlag == 1)
322 close(TelPortFD);
323 TelConnectFlag = 0;
324}
325
326
327/* Test update status and return the telescope right ascension */
328/* Set updateRA flag false */
329/* Last telescope readout will be returned if no RA inquiry since then */
330/* Otherwise force a new readout */
331/* Two successive calls to GetRA will always force a new readout */
332
333double GetRA(void)
334{
335 if( updateRA != 1) GetRAandDec();
336 updateRA = 0;
337 return returnRA;
338}
339
340
341/* Test update status and return the telescope declination */
342/* Set updateDec flag false */
343/* Last telescope readout will returned if no Dec inquiry since then */
344/* Otherwise force a new readout */
345/* Two successive calls to GetDec will always force a new readout */
346
347double GetDec(void)
348{
349 if( updateDec != 1) GetRAandDec();
350 updateDec = 0;
351 return returnDec;
352}
353
354
355/* Read the telescope right ascension and declination and set update status */
356
357void GetRAandDec(void)
358{
359 char returnStr[12];
360 int countRA,countDec;
361 int numRead;
362
363 writen(TelPortFD,"E",1);
364 numRead=readn(TelPortFD,returnStr,10,1);
365 returnStr[4] = returnStr[9] = '\0';
366
367/* Diagnostic
368 *
369 * printf("GetRAandDec: %d read %x\n",numRead,returnStr);
370 *
371 */
372
373 sscanf(returnStr,"%x",&countRA);
374 sscanf(returnStr+5,"%x:",&countDec);
375 returnRA = (double) countRA;
376 returnRA = returnRA / (3. * 15. * 60. * 65536./64800.);
377 returnDec = (double) countDec;
378 returnDec = returnDec / (3. * 60. * 65536./64800.);
379
380
381/* Account for the quadrant in declination */
382
383/* 90 to 180 */
384
385 if ( (returnDec > 90.) && (returnDec <= 180.) )
386 {
387 returnDec = 180. - returnDec;
388 }
389
390
391/* 180 to 270 */
392
393 if ( (returnDec > 180.) && (returnDec <= 270.) )
394 {
395 returnDec = returnDec - 270.;
396 }
397
398
399/* 270 to 360 */
400
401 if ( (returnDec > 270.) && (returnDec <= 360.) )
402 {
403 returnDec = returnDec - 360.;
404 }
405
406
407/* Set update flags */
408
409 updateRA = 1;
410 updateDec = 1;
411
412
413/* Correct for offsets and return true coordinate */
414/* Coordinate reported by NexStar = true coordinate + offset. */
415
416 returnRA = returnRA - offsetRA;
417 returnDec = returnDec - offsetDec;
418
419}
420
421
422
423/* Reset telescope coordinates to new coordinates by adjusting offsets*/
424/* Coordinate reported by NexStar = true coordinate + offset. */
425
426int SyncToCoords(double newRA, double newDec)
427{
428 offsetRA = 0.;
429 offsetDec = 0.;
430 GetRAandDec();
431 offsetRA = returnRA - newRA;
432 offsetDec = returnDec - newDec;
433
434 return (0);
435}
436
437
438/* Slew to new coordinates */
439/* Coordinate sent to NexStar = true coordinate + offset. */
440
441int SlewToCoords(double newRA, double newDec)
442{
443 int countRA,countDec;
444 char r0,r1,r2,r3,d0,d1,d2,d3;
445 double degs, hrs;
446 char outputStr[32], inputStr[2048];
447
448 /* Add offsets */
449
450 hrs = newRA + offsetRA;
451 degs = newDec + offsetDec;
452
453 /* Convert float RA to integer count */
454
455 hrs = hrs*(3. * 15. * 60. * 65536./64800.);
456 countRA = (int) hrs;
457
458
459/* Account for the quadrant in declination */
460
461 if ( (newDec >= 0.0) && (newDec <= 90.0) )
462 {
463 degs = degs*(3. * 60. * 65536./64800.);
464 }
465 else if ( (newDec < 0.0) && (newDec >= -90.0) )
466 {
467 degs = (360. + degs)*(3. * 60. * 65536./64800.);
468 }
469 else
470 {
471 fprintf(stderr,"Invalid newDec in SlewToCoords.\n");
472 return 1;
473 }
474
475
476
477 /* Convert float Declination to integer count */
478
479 countDec = (int) degs;
480
481
482 /* Convert each integer count to four HEX characters */
483 /* Inline coding just to be fast */
484
485
486 if(countRA < 65536)
487 {
488 r0 = countRA % 16;
489 if(r0 < 10)
490 {
491 r0 = r0 + 48;
492 }
493 else
494 {
495 r0 = r0 + 55;
496 }
497 countRA = countRA/16;
498 r1 = countRA % 16;
499 if(r1 < 10)
500 {
501 r1 = r1 + 48;
502 }
503 else
504 {
505 r1 = r1 + 55;
506 }
507 countRA = countRA/16;
508 r2 = countRA % 16;
509 if(r2 < 10)
510 {
511 r2 = r2 + 48;
512 }
513 else
514 {
515 r2 = r2 + 55;
516 }
517 r3 = countRA/16;
518 if(r3 < 10)
519 {
520 r3 = r3 + 48;
521 }
522 else
523 {
524 r3 = r3 + 55;
525 }
526 }
527 else
528 {
529 printf("RA count overflow in SlewToCoords.\n");
530 return 2;
531 }
532 if(countDec < 65536)
533 {
534 d0 = countDec % 16;
535 if(d0 < 10)
536 {
537 d0 = d0 + 48;
538 }
539 else
540 {
541 d0 = d0 + 55;
542 }
543 countDec = countDec/16;
544 d1 = countDec % 16;
545 if(d1 < 10)
546 {
547 d1 = d1 + 48;
548 }
549 else
550 {
551 d1 = d1 + 55;
552 }
553 countDec = countDec/16;
554 d2 = countDec % 16;
555 if(d2 < 10)
556 {
557 d2 = d2 + 48;
558 }
559 else
560 {
561 d2 = d2 + 55;
562 }
563 d3 = countDec/16;
564 if(d3 < 10)
565 {
566 d3 = d3 + 48;
567 }
568 else
569 {
570 d3 = d3 + 55;
571 }
572 }
573 else
574 {
575 fprintf(stderr,"Dec count overflow in SlewToCoords.\n");
576 return 3;
577 }
578
579
580
581 /* Send the command and characters to the NexStar */
582
583 sprintf(outputStr,"R%c%c%c%c,%c%c%c%c",r3,r2,r1,r0,d3,d2,d1,d0);
584 writen(TelPortFD,outputStr,10);
585
586 /* Look for '#' in response */
587
588 for (;;)
589 {
590 if ( readn(TelPortFD,inputStr,1,2) )
591 {
592 if (inputStr[0] == '#') break;
593 }
594 else
595 fprintf(stderr,"No acknowledgment from telescope after SlewToCoords.\n");
596 return 4;
597 }
598 return 0;
599}
600
601
602/* Test whether the destination has been reached */
603/* With the NexStar we use the goto in progress query */
604/* Return value is */
605/* 0 -- goto in progress */
606/* 1 -- goto complete within tolerance */
607/* 2 -- goto complete but outside tolerance */
608
609int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC)
610{
611 double errorRA, errorDec, nowRA, nowDec;
612 char inputStr[2048];
613
614 writen(TelPortFD,"L",1);
615
616 /* Look for '0#' in response indicating goto is not in progress */
617
618 for (;;)
619 {
620 if ( readn(TelPortFD,inputStr,2,2) )
621 {
622 if ( (inputStr[0] == '0') && (inputStr[1] == '#')) break;
623 }
624 else
625 return 0;
626 }
627
628
629 nowRA=GetRA();
630 errorRA = nowRA - desRA;
631 nowDec=GetDec();
632 errorDec = nowDec - desDec;
633
634
635 /* For 6 minute of arc precision; change as needed. */
636
637 if( fabs(errorRA) > tolRA || fabs(errorDec) > tolDEC)
638 return 1;
639 else
640 return 2;
641}
642
643
644/* Set lower and upper limits to protect hardware */
645
646void SetLimits(double limitLower, double limitHigher)
647{
648 limitLower = limitHigher;
649 fprintf(stderr,"NexStar does not support software limits.\n");
650}
651
652
653/* Set slew speed limited by MAXSLEWRATE */
654
655int SetSlewRate(void)
656{
657 fprintf(stderr,"NexStar does not support remote setting of slew rate.\n");
658 return 0;
659}
660
661
662
663/* Stop all slew motion */
664
665void StopNSEW(void)
666{
667 char inputStr[2048];
668
669 writen(TelPortFD,"M",1);
670
671 /* Look for '#' */
672
673 for (;;)
674 {
675 if ( readn(TelPortFD,inputStr,1,1) )
676 {
677 if (inputStr[0] == '#') break;
678 }
679 else
680 {
681 fprintf(stderr,"No acknowledgment from telescope in StopNSEW.\n");
682 }
683 }
684}
685
686
687
688/* Control the reticle function using predefined values */
689
690void Reticle(int reticle)
691{
692 reticle = reticle;
693 fprintf(stderr,"NexStar does not support remote setting of reticle.\n");
694}
695
696
697/* Control the focus using predefined values */
698
699void Focus(int focus)
700{
701 focus = focus;
702 fprintf(stderr,"NexStar does not support remote setting of focus.\n");
703}
704
705
706
707/* Control the derotator using predefined values */
708
709void Derotator(int rotate)
710
711{
712 rotate = rotate;
713 fprintf(stderr,"NexStar does not support an image derotator.\n");
714}
715
716
717/* Control the fan using predefined values */
718
719void Fan(int fan)
720
721{
722 fan = fan;
723 fprintf(stderr,"NexStar does not have a fan.\n");
724}
725
726
727/* Time synchronization utilities */
728
729/* Reset the telescope sidereal time */
730
731int SyncLST(double newTime)
732{
733 newTime = newTime;
734 fprintf(stderr,"NexStar does not support remote setting of sidereal time.\n");
735 return -1;
736}
737
738
739/* Reset the telescope local time */
740
741int SyncLocalTime()
742{
743 fprintf(stderr,"NexStar does not support remote setting of local time.\n");
744 return -1;
745}
746
747
748
749
750/* Serial port utilities */
751
752static int writen(fd, ptr, nbytes)
753int fd;
754char *ptr;
755int nbytes;
756{
757 int nleft, nwritten;
758 nleft = nbytes;
759 while (nleft > 0)
760 {
761 nwritten = write (fd, ptr, nleft);
762 if (nwritten <=0 ) break;
763 nleft -= nwritten;
764 ptr += nwritten;
765 }
766 return (nbytes - nleft);
767}
768
769static int readn(fd, ptr, nbytes, sec)
770int fd;
771char *ptr;
772int nbytes;
773int sec;
774{
775 int status;
776 int nleft, nread;
777 nleft = nbytes;
778 while (nleft > 0)
779 {
780 status = telstat(fd,sec,0);
781 if (status <= 0 ) break;
782 nread = read (fd, ptr, nleft);
783
784/* Diagnostic */
785
786/* printf("readn: %d read\n", nread); */
787
788 if (nread <= 0) break;
789 nleft -= nread;
790 ptr += nread;
791 }
792 return (nbytes - nleft);
793}
794
795/*
796 * Examines the read status of a file descriptor.
797 * The timeout (sec, usec) specifies a maximum interval to
798 * wait for data to be available in the descriptor.
799 * To effect a poll, the timeout (sec, usec) should be 0.
800 * Returns non-negative value on data available.
801 * 0 indicates that the time limit referred by timeout expired.
802 * On failure, it returns -1 and errno is set to indicate the
803 * error.
804 */
805static int telstat(fd,sec,usec)
806register int fd, sec, usec;
807{
808 int ret;
809 int width;
810 struct timeval timeout;
811 telfds readfds;
812
813 memset((char *)&readfds,0,sizeof(readfds));
814 FD_SET(fd, &readfds);
815 width = fd+1;
816 timeout.tv_sec = sec;
817 timeout.tv_usec = usec;
818 ret = select(width,&readfds,NULL_PTR(telfds),NULL_PTR(telfds),&timeout);
819 return(ret);
820}
821
Note: See TracBrowser for help on using the repository browser.