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

Last change on this file since 614 was 490, checked in by campagne, 14 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.