3 Copyright (C
) 2003 Jasem
Mutlaq (mutlaqja@ikarustech
.com
)
5 This library is free software
; you can redistribute it
and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation
; either
8 version
2.1 of the License
, or (at your option
) any later version
.
10 This library is distributed in the hope that it will be useful
,
11 but WITHOUT ANY WARRANTY
; without even the implied warranty of
12 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE
. See the GNU
13 Lesser General Public License
for more details
.
15 You should have received a copy of the GNU Lesser General Public
16 License along with
this library
; if not, write to the Free Software
17 Foundation
, Inc
., 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
33 #include "indidevapi.h"
34 #include "lx200driver.h"
36 #define LX200_TIMEOUT 5 /* FD timeout in seconds */
39 int read_ret
, write_ret
;
41 /**************************************************************************
43 **************************************************************************/
44 int openPort(const char *portID
);
45 int portRead(char *buf
, int nbytes
, int timeout
);
46 int portWrite(const char * buf
);
47 int LX200readOut(int timeout
);
49 int Connect(const char* device
);
50 void Disconnect(void);
52 /**************************************************************************
54 **************************************************************************/
56 int testTelescope(void);
59 /**************************************************************************
60 Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure
61 **************************************************************************/
63 /* Get Double from Sexagisemal */
64 int getCommandSexa(double *value
, const char *cmd
);
66 int getCommandString(char *data
, const char* cmd
);
68 int getCommandInt(int *value
, const char* cmd
);
69 /* Get tracking frequency */
70 int getTrackFreq(double * value
);
71 /* Get site Latitude */
72 int getSiteLatitude(int *dd
, int *mm
);
73 /* Get site Longitude */
74 int getSiteLongitude(int *ddd
, int *mm
);
75 /* Get Calender data */
76 int getCalenderDate(char *date
);
78 int getSiteName(char *siteName
, int siteNum
);
79 /* Get Number of Bars */
80 int getNumberOfBars(int *value
);
81 /* Get Home Search Status */
82 int getHomeSearchStatus(int *status
);
83 /* Get OTA Temperature */
84 int getOTATemp(double * value
);
85 /* Get time format: 12 or 24 */
86 int getTimeFormat(int *format
);
89 /**************************************************************************
91 **************************************************************************/
94 int setCommandInt(int data
, const char *cmd
);
96 int setCommandXYZ( int x
, int y
, int z
, const char *cmd
);
97 /* Common routine for Set commands */
98 int setStandardProcedure(char * writeData
);
100 int setSlewMode(int slewMode
);
101 /* Set Alignment mode */
102 int setAlignmentMode(unsigned int alignMode
);
104 int setObjectRA(double ra
);
106 int setObjectDEC(double dec
);
107 /* Set Calender date */
108 int setCalenderDate(int dd
, int mm
, int yy
);
110 int setUTCOffset(double hours
);
112 int setTrackFreq(double trackF
);
113 /* Set current site longitude */
114 int setSiteLongitude(double Long
);
115 /* Set current site latitude */
116 int setSiteLatitude(double Lat
);
117 /* Set Object Azimuth */
118 int setObjAz(double az
);
119 /* Set Object Altitude */
120 int setObjAlt(double alt
);
122 int setSiteName(char * siteName
, int siteNum
);
123 /* Set maximum slew rate */
124 int setMaxSlewRate(int slewRate
);
125 /* Set focuser motion */
126 int setFocuserMotion(int motionType
);
127 /* Set focuser speed mode */
128 int setFocuserSpeedMode (int speedMode
);
129 /* Set minimum elevation limit */
130 int setMinElevationLimit(int min
);
131 /* Set maximum elevation limit */
132 int setMaxElevationLimit(int max
);
134 /**************************************************************************
136 **************************************************************************/
137 /* Slew to the selected coordinates */
139 /* Synchronize to the selected coordinates and return the matching object if any */
140 int Sync(char *matchedObject
);
141 /* Abort slew in all axes */
143 /* Move into one direction, two valid directions can be stacked */
144 int MoveTo(int direction
);
145 /* Half movement in a particular direction */
146 int HaltMovement(int direction
);
147 /* Select the tracking mode */
148 int selectTrackingMode(int trackMode
);
149 /* Select Astro-Physics tracking mode */
150 int selectAPTrackingMode(int trackMode
);
152 /**************************************************************************
154 **************************************************************************/
155 /* Ensures LX200 RA/DEC format is long */
156 int checkLX200Format(void);
157 /* Select a site from the LX200 controller */
158 int selectSite(int siteNum
);
159 /* Select a catalog object */
160 int selectCatalogObject(int catalog
, int NNNN
);
161 /* Select a sub catalog */
162 int selectSubCatalog(int catalog
, int subCatalog
);
164 /**********************************************************************
166 **********************************************************************/
168 int Connect(const char *device
)
170 fprintf(stderr
, "Connecting to device %s\n", device
);
172 if (openPort(device
) < 0)
180 fprintf(stderr
, "Disconnected.\n");
187 char ack
[1] = { (char) 0x06 };
189 fprintf(stderr
, "Testing telescope's connection...\n");
191 for (i
=0; i
< 2; i
++)
194 read_ret
= portRead(MountAlign
, 1, LX200_TIMEOUT
);
206 char currentDate
[64];
208 fprintf(stderr
, "Testing telescope's connection...\n");
210 /* We need to test if the telescope is responding
211 / We're going to request the calander date */
212 for (i
=0; i
< 2; i
++)
214 if (!getCalenderDate(currentDate
))
225 /**********************************************************************
227 **********************************************************************/
231 char ack
[1] = { (char) 0x06 };
234 write_ret
= write(fd
, ack
, 1);
239 read_ret
= portRead(MountAlign
, 1, LX200_TIMEOUT
);
242 return MountAlign
[0];
248 int getCommandSexa(double *value
, const char * cmd
)
252 tcflush(fd
, TCIFLUSH
);
254 if (portWrite(cmd
) < 0)
257 if ( (read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
)) < 1)
260 tempString
[read_ret
- 1] = '\0';
262 if (f_scansexa(tempString
, value
))
264 fprintf(stderr
, "unable to process [%s]\n", tempString
);
271 int getCommandString(char *data
, const char* cmd
)
275 if (portWrite(cmd
) < 0)
278 read_ret
= portRead(data
, -1, LX200_TIMEOUT
);
283 term
= strchr (data
, '#');
287 fprintf(stderr
, "Requested data: %s\n", data
);
292 int getCalenderDate(char *date
)
298 if ( (err
= getCommandString(date
, "#:GC#")) )
301 /* Meade format is MM/DD/YY */
303 read_ret
= sscanf(date
, "%d%*c%d%*c%d", &mm
, &dd
, &yy
);
307 /* We need to have in in YYYY/MM/DD format */
308 sprintf(date
, "20%02d/%02d/%02d", yy
, mm
, dd
);
314 int getTimeFormat(int *format
)
319 if (portWrite("#:Gc#") < 0)
322 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
327 tempString
[read_ret
-1] = '\0';
329 read_ret
= sscanf(tempString
, "(%d)", &tMode
);
347 read_ret = portRead(tempString, 4);
351 tempString[3] = '\0';
353 sscanf(tempString, "%d", &offSet);
355 fprintf(stderr, "UTC Offset: %d\n", offSet);
360 int getMaxElevationLimit()
367 read_ret = portRead(tempString, -1, LX200_TIMEOUT);
371 tempString[read_ret-1] = '\0';
373 sscanf(tempString, "%d", &limit);
375 fprintf(stderr, "Max elevation limit string is %s\n", tempString);
380 int getMinElevationLimit()
387 read_ret = portRead(tempString, -1, LX200_TIMEOUT);
391 tempString[read_ret-1] = '\0';
393 sscanf(tempString, "%d", &limit);
395 fprintf(stderr, "Min elevation limit string is %s\n", tempString);
402 int getSiteName(char *siteName
, int siteNum
)
409 if (portWrite("#:GM#") < 0)
413 if (portWrite("#:GN#") < 0)
417 if (portWrite("#:GO#") < 0)
421 if (portWrite("#:GP#") < 0)
428 read_ret
= portRead(siteName
, -1, LX200_TIMEOUT
);
432 siteName
[read_ret
- 1] = '\0';
434 term
= strchr (siteName
, ' ');
438 term
= strchr (siteName
, '<');
440 strcpy(siteName
, "unused site");
442 fprintf(stderr
, "Requested site name: %s\n", siteName
);
447 int getSiteLatitude(int *dd
, int *mm
)
451 if (portWrite("#:Gt#") < 0)
454 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
459 tempString
[read_ret
-1] = '\0';
461 if (sscanf (tempString
, "%d%*c%d", dd
, mm
) < 2)
464 fprintf(stderr
, "Requested site latitude in String %s\n", tempString
);
465 fprintf(stderr
, "Requested site latitude %d:%d\n", *dd
, *mm
);
470 int getSiteLongitude(int *ddd
, int *mm
)
474 if (portWrite("#:Gg#") < 0)
477 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
482 tempString
[read_ret
-1] = '\0';
484 if (sscanf (tempString
, "%d%*c%d", ddd
, mm
) < 2)
487 fprintf(stderr
, "Requested site longitude in String %s\n", tempString
);
488 fprintf(stderr
, "Requested site longitude %d:%d\n", *ddd
, *mm
);
493 int getTrackFreq(double *value
)
498 if (portWrite("#:GT#") < 0)
501 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
506 tempString
[read_ret
] = '\0';
508 /*fprintf(stderr, "Telescope tracking freq str: %s\n", tempString);*/
510 if (sscanf(tempString
, "%f#", &Freq
) < 1)
513 *value
= (double) Freq
;
515 /*fprintf(stderr, "Tracking frequency value is %f\n", Freq);*/
520 int getNumberOfBars(int *value
)
522 char tempString
[128];
524 if (portWrite("#:D#") < 0)
527 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
532 *value
= read_ret
-1;
537 int getHomeSearchStatus(int *status
)
541 if (portWrite("#:h?#") < 0)
544 read_ret
= portRead(tempString
, 1, LX200_TIMEOUT
);
549 tempString
[1] = '\0';
551 if (tempString
[0] == '0')
553 else if (tempString
[0] == '1')
555 else if (tempString
[0] == '2')
561 int getOTATemp(double *value
)
567 if (portWrite("#:fT#") < 0)
570 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
575 tempString
[read_ret
- 1] = '\0';
577 if (sscanf(tempString
, "%f", &temp
) < 1)
580 *value
= (double) temp
;
586 /**********************************************************************
588 **********************************************************************/
590 int setStandardProcedure(char * data
)
594 if (portWrite(data
) < 0)
597 read_ret
= portRead(boolRet
, 1, LX200_TIMEOUT
);
602 if (boolRet
[0] == '0')
604 fprintf(stderr
, "%s Failed.\n", data
);
608 fprintf(stderr
, "%s Successful\n", data
);
614 int setCommandInt(int data
, const char *cmd
)
619 snprintf(tempString
, sizeof( tempString
), "%s%d#", cmd
, data
);
621 if (portWrite(tempString
) < 0)
627 int setMinElevationLimit(int min
)
631 snprintf(tempString
, sizeof( tempString
), "#:Sh%02d#", min
);
633 return (setStandardProcedure(tempString
));
636 int setMaxElevationLimit(int max
)
640 snprintf(tempString
, sizeof( tempString
), "#:So%02d*#", max
);
642 return (setStandardProcedure(tempString
));
646 int setMaxSlewRate(int slewRate
)
651 if (slewRate
< 2 || slewRate
> 8)
654 snprintf(tempString
, sizeof( tempString
), "#:Sw%d#", slewRate
);
656 return (setStandardProcedure(tempString
));
661 int setObjectRA(double ra
)
667 getSexComponents(ra
, &h
, &m
, &s
);
669 snprintf(tempString
, sizeof( tempString
), "#:Sr %02d:%02d:%02d#", h
, m
, s
);
670 IDLog("Set Object RA String %s\n", tempString
);
671 return (setStandardProcedure(tempString
));
675 int setObjectDEC(double dec
)
680 getSexComponents(dec
, &d
, &m
, &s
);
682 /* case with negative zero */
684 snprintf(tempString
, sizeof( tempString
), "#:Sd -%02d:%02d:%02d#", d
, m
, s
);
686 snprintf(tempString
, sizeof( tempString
), "#:Sd %+03d:%02d:%02d#", d
, m
, s
);
688 IDLog("Set Object DEC String %s\n", tempString
);
690 return (setStandardProcedure(tempString
));
694 int setCommandXYZ(int x
, int y
, int z
, const char *cmd
)
698 snprintf(tempString
, sizeof( tempString
), "%s %02d:%02d:%02d#", cmd
, x
, y
, z
);
700 return (setStandardProcedure(tempString
));
703 int setAlignmentMode(unsigned int alignMode
)
705 fprintf(stderr
, "Set alignment mode %d\n", alignMode
);
709 case LX200_ALIGN_POLAR
:
710 if (portWrite("#:AP#") < 0)
713 case LX200_ALIGN_ALTAZ
:
714 if (portWrite("#:AA#") < 0)
717 case LX200_ALIGN_LAND
:
718 if (portWrite("#:AL#") < 0)
726 int setCalenderDate(int dd
, int mm
, int yy
)
729 char dumpPlanetaryUpdateString
[64];
733 snprintf(tempString
, sizeof( tempString
), "#:SC %02d/%02d/%02d#", mm
, dd
, yy
);
735 if (portWrite(tempString
) < 0)
738 read_ret
= portRead(boolRet
, 1, LX200_TIMEOUT
);
745 if (boolRet
[0] == '0')
748 /* Read dumped data */
749 portRead(dumpPlanetaryUpdateString
, -1, LX200_TIMEOUT
);
750 portRead(dumpPlanetaryUpdateString
, -1, 5);
755 int setUTCOffset(double hours
)
759 /*TODO add fractions*/
760 snprintf(tempString
, sizeof( tempString
), "#:SG %+03d#", (int) hours
);
762 fprintf(stderr
, "UTC string is %s\n", tempString
);
764 return (setStandardProcedure(tempString
));
768 int setSiteLongitude(double Long
)
773 getSexComponents(Long
, &d
, &m
, &s
);
775 snprintf(tempString
, sizeof( tempString
), "#:Sg%03d:%02d#", d
, m
);
777 return (setStandardProcedure(tempString
));
780 int setSiteLatitude(double Lat
)
785 getSexComponents(Lat
, &d
, &m
, &s
);
787 snprintf(tempString
, sizeof( tempString
), "#:St%+03d:%02d:%02d#", d
, m
, s
);
789 return (setStandardProcedure(tempString
));
792 int setObjAz(double az
)
797 getSexComponents(az
, &d
, &m
, &s
);
799 snprintf(tempString
, sizeof( tempString
), "#:Sz%03d:%02d#", d
, m
);
801 return (setStandardProcedure(tempString
));
805 int setObjAlt(double alt
)
810 getSexComponents(alt
, &d
, &m
, &s
);
812 snprintf(tempString
, sizeof( tempString
), "#:Sa%+02d*%02d#", d
, m
);
814 return (setStandardProcedure(tempString
));
818 int setSiteName(char * siteName
, int siteNum
)
826 snprintf(tempString
, sizeof( tempString
), "#:SM %s#", siteName
);
829 snprintf(tempString
, sizeof( tempString
), "#:SN %s#", siteName
);
832 snprintf(tempString
, sizeof( tempString
), "#:SO %s#", siteName
);
835 snprintf(tempString
, sizeof( tempString
), "#:SP %s#", siteName
);
841 return (setStandardProcedure(tempString
));
844 int setSlewMode(int slewMode
)
850 if (portWrite("#:RS#") < 0)
853 case LX200_SLEW_FIND
:
854 if (portWrite("#:RM#") < 0)
857 case LX200_SLEW_CENTER
:
858 if (portWrite("#:RC#") < 0)
861 case LX200_SLEW_GUIDE
:
862 if (portWrite("#:RG#") < 0)
873 int setFocuserMotion(int motionType
)
879 if (portWrite("#:F+#") < 0)
883 if (portWrite("#:F-#") < 0)
891 int setFocuserSpeedMode (int speedMode
)
896 case LX200_HALTFOCUS
:
897 if (portWrite("#:FQ#") < 0)
900 case LX200_FOCUSFAST
:
901 if (portWrite("#:FF#") < 0)
904 case LX200_FOCUSMEDIUM
:
905 if (portWrite("#:F3#") < 0)
908 case LX200_FOCUSSLOW
:
909 if (portWrite("#:FS#") < 0)
918 int setTrackFreq(double trackF
)
922 snprintf(tempString
, sizeof( tempString
), "#:ST %04.1f#", trackF
);
924 return (setStandardProcedure(tempString
));
928 /**********************************************************************
930 *********************************************************************/
937 if (portWrite("#:MS#") < 0)
940 read_ret
= portRead(slewNum
, 1, LX200_TIMEOUT
);
947 if (slewNum
[0] == '0')
950 read_ret
= portRead(errorMsg
, -1, LX200_TIMEOUT
);
955 if (slewNum
[0] == '1')
961 int MoveTo(int direction
)
985 int HaltMovement(int direction
)
991 if (portWrite("#:Qn#") < 0)
995 if (portWrite("#:Qw#") < 0)
999 if (portWrite("#:Qe#") < 0)
1003 if (portWrite("#:Qs#") < 0)
1007 if (portWrite("#:Q#") < 0)
1021 if (portWrite("#:Q#") < 0)
1027 int Sync(char *matchedObject
)
1031 read_ret
= portRead(matchedObject
, -1, LX200_TIMEOUT
);
1036 matchedObject
[read_ret
-1] = '\0';
1038 /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
1041 tcflush(fd
, TCIFLUSH
);
1046 int selectSite(int siteNum
)
1052 if (portWrite("#:W1#") < 0)
1056 if (portWrite("#:W2#") < 0)
1060 if (portWrite("#:W3#") < 0)
1064 if (portWrite("#:W4#") < 0)
1076 int selectCatalogObject(int catalog
, int NNNN
)
1078 char tempString
[16];
1083 snprintf(tempString
, sizeof( tempString
), "#:LS%d#", NNNN
);
1085 case LX200_DEEPSKY_C
:
1086 snprintf(tempString
, sizeof( tempString
), "#:LC%d#", NNNN
);
1088 case LX200_MESSIER_C
:
1089 snprintf(tempString
, sizeof( tempString
), "#:LM%d#", NNNN
);
1095 if (portWrite(tempString
) < 0)
1101 int selectSubCatalog(int catalog
, int subCatalog
)
1103 char tempString
[16];
1107 snprintf(tempString
, sizeof( tempString
), "#:LsD%d#", subCatalog
);
1109 case LX200_DEEPSKY_C
:
1110 snprintf(tempString
, sizeof( tempString
), "#:LoD%d#", subCatalog
);
1112 case LX200_MESSIER_C
:
1118 return (setStandardProcedure(tempString
));
1121 int checkLX200Format()
1124 char tempString
[16];
1126 if (portWrite("#:GR#") < 0)
1129 read_ret
= portRead(tempString
, -1, LX200_TIMEOUT
);
1134 tempString
[read_ret
- 1] = '\0';
1137 if (tempString
[5] == '.')
1138 if (portWrite("#:U#") < 0)
1144 int selectTrackingMode(int trackMode
)
1149 case LX200_TRACK_DEFAULT
:
1150 fprintf(stderr
, "Setting tracking mode to sidereal.\n");
1151 if (portWrite("#:TQ#") < 0)
1154 case LX200_TRACK_LUNAR
:
1155 fprintf(stderr
, "Setting tracking mode to LUNAR.\n");
1156 if (portWrite("#:TL#") < 0)
1159 case LX200_TRACK_MANUAL
:
1160 fprintf(stderr
, "Setting tracking mode to CUSTOM.\n");
1161 if (portWrite("#:TM#") < 0)
1173 int selectAPTrackingMode(int trackMode
)
1179 fprintf(stderr
, "Setting tracking mode to lunar.\n");
1180 if (portWrite("#:RT0#") < 0)
1186 fprintf(stderr
, "Setting tracking mode to solar.\n");
1187 if (portWrite("#:RT1#") < 0)
1193 fprintf(stderr
, "Setting tracking mode to sidereal.\n");
1194 if (portWrite("#:RT2#") < 0)
1200 fprintf(stderr
, "Setting tracking mode to zero.\n");
1201 if (portWrite("#:RT9#") < 0)
1215 /**********************************************************************
1217 **********************************************************************/
1219 int openPort(const char *portID
)
1221 struct termios ttyOptions
;
1223 if ( (fd
= open(portID
, O_RDWR
)) == -1)
1226 memset(&ttyOptions
, 0, sizeof(ttyOptions
));
1227 tcgetattr(fd
, &ttyOptions
);
1231 ttyOptions
.c_cflag
&= ~CSIZE
;
1232 /* 8 bit, enable read */
1233 ttyOptions
.c_cflag
|= CREAD
| CLOCAL
| CS8
;
1235 ttyOptions
.c_cflag
&= ~PARENB
;
1238 cfsetispeed(&ttyOptions
, B9600
);
1239 cfsetospeed(&ttyOptions
, B9600
);
1241 /* set input/output flags */
1242 ttyOptions
.c_iflag
= IGNBRK
;
1243 /* no software flow control */
1244 ttyOptions
.c_iflag
&= ~(IXON
|IXOFF
|IXANY
);
1246 /* Read at least one byte */
1247 ttyOptions
.c_cc
[VMIN
] = 1;
1248 ttyOptions
.c_cc
[VTIME
] = 5;
1251 ttyOptions
.c_lflag
= 0;
1252 ttyOptions
.c_oflag
= 0;
1254 /* set attributes */
1255 tcsetattr(fd
, TCSANOW
, &ttyOptions
);
1257 /* flush the channel */
1258 tcflush(fd
, TCIOFLUSH
);
1262 int portWrite(const char * buf
)
1264 int nbytes
, totalBytesWritten
;
1265 int bytesWritten
= 0;
1267 nbytes
= totalBytesWritten
= strlen(buf
);
1272 bytesWritten
= write(fd
, buf
, nbytes
);
1274 if (bytesWritten
< 0)
1277 buf
+= bytesWritten
;
1278 nbytes
-= bytesWritten
;
1281 /* Returns the # of bytes written */
1282 return (totalBytesWritten
);
1285 int portRead(char *buf
, int nbytes
, int timeout
)
1289 int totalBytesRead
= 0;
1292 /* Loop until encountring the '#' char */
1297 if ( (err
= LX200readOut(timeout
)) )
1300 bytesRead
= read(fd
, buf
, 1);
1309 return totalBytesRead
;
1317 if ( (err
= LX200readOut(timeout
)) )
1320 bytesRead
= read(fd
, buf
, nbytes
);
1327 nbytes
-= bytesRead
;
1330 return totalBytesRead
;
1333 int LX200readOut(int timeout
)
1340 FD_SET(fd
, &readout
);
1342 /* wait for 'timeout' seconds */
1343 tv
.tv_sec
= timeout
;
1346 /* Wait till we have a change in the fd status */
1347 retval
= select (fd
+1, &readout
, NULL
, NULL
, &tv
);
1349 /* Return 0 on successful fd change */
1352 /* Return -1 due to an error */
1353 else if (retval
== -1)
1355 /* Return -2 if time expires before anything interesting happens */