summaryrefslogtreecommitdiffstats
path: root/kstars/kstars/indi/lx200driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'kstars/kstars/indi/lx200driver.c')
-rw-r--r--kstars/kstars/indi/lx200driver.c1386
1 files changed, 1386 insertions, 0 deletions
diff --git a/kstars/kstars/indi/lx200driver.c b/kstars/kstars/indi/lx200driver.c
new file mode 100644
index 00000000..9c521cfe
--- /dev/null
+++ b/kstars/kstars/indi/lx200driver.c
@@ -0,0 +1,1386 @@
+#if 0
+ LX200 Driver
+ Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <time.h>
+
+#include "indicom.h"
+#include "indidevapi.h"
+#include "lx200driver.h"
+
+#define LX200_TIMEOUT 5 /* FD timeout in seconds */
+
+int fd;
+int read_ret, write_ret;
+
+/**************************************************************************
+ Basic I/O
+**************************************************************************/
+int openPort(const char *portID);
+int portRead(char *buf, int nbytes, int timeout);
+int portWrite(const char * buf);
+int LX200readOut(int timeout);
+
+int Connect(const char* device);
+void Disconnect(void);
+
+/**************************************************************************
+ Diagnostics
+ **************************************************************************/
+char ACK(void);
+int testTelescope(void);
+int testAP(void);
+
+/**************************************************************************
+ Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure
+ **************************************************************************/
+
+/* Get Double from Sexagisemal */
+int getCommandSexa(double *value, const char *cmd);
+/* Get String */
+int getCommandString(char *data, const char* cmd);
+/* Get Int */
+int getCommandInt(int *value, const char* cmd);
+/* Get tracking frequency */
+int getTrackFreq(double * value);
+/* Get site Latitude */
+int getSiteLatitude(int *dd, int *mm);
+/* Get site Longitude */
+int getSiteLongitude(int *ddd, int *mm);
+/* Get Calender data */
+int getCalenderDate(char *date);
+/* Get site Name */
+int getSiteName(char *siteName, int siteNum);
+/* Get Number of Bars */
+int getNumberOfBars(int *value);
+/* Get Home Search Status */
+int getHomeSearchStatus(int *status);
+/* Get OTA Temperature */
+int getOTATemp(double * value);
+/* Get time format: 12 or 24 */
+int getTimeFormat(int *format);
+
+
+/**************************************************************************
+ Set Commands
+ **************************************************************************/
+
+/* Set Int */
+int setCommandInt(int data, const char *cmd);
+/* Set Sexigesimal */
+int setCommandXYZ( int x, int y, int z, const char *cmd);
+/* Common routine for Set commands */
+int setStandardProcedure(char * writeData);
+/* Set Slew Mode */
+int setSlewMode(int slewMode);
+/* Set Alignment mode */
+int setAlignmentMode(unsigned int alignMode);
+/* Set Object RA */
+int setObjectRA(double ra);
+/* set Object DEC */
+int setObjectDEC(double dec);
+/* Set Calender date */
+int setCalenderDate(int dd, int mm, int yy);
+/* Set UTC offset */
+int setUTCOffset(double hours);
+/* Set Track Freq */
+int setTrackFreq(double trackF);
+/* Set current site longitude */
+int setSiteLongitude(double Long);
+/* Set current site latitude */
+int setSiteLatitude(double Lat);
+/* Set Object Azimuth */
+int setObjAz(double az);
+/* Set Object Altitude */
+int setObjAlt(double alt);
+/* Set site name */
+int setSiteName(char * siteName, int siteNum);
+/* Set maximum slew rate */
+int setMaxSlewRate(int slewRate);
+/* Set focuser motion */
+int setFocuserMotion(int motionType);
+/* Set focuser speed mode */
+int setFocuserSpeedMode (int speedMode);
+/* Set minimum elevation limit */
+int setMinElevationLimit(int min);
+/* Set maximum elevation limit */
+int setMaxElevationLimit(int max);
+
+/**************************************************************************
+ Motion Commands
+ **************************************************************************/
+/* Slew to the selected coordinates */
+int Slew(void);
+/* Synchronize to the selected coordinates and return the matching object if any */
+int Sync(char *matchedObject);
+/* Abort slew in all axes */
+int abortSlew(void);
+/* Move into one direction, two valid directions can be stacked */
+int MoveTo(int direction);
+/* Half movement in a particular direction */
+int HaltMovement(int direction);
+/* Select the tracking mode */
+int selectTrackingMode(int trackMode);
+/* Select Astro-Physics tracking mode */
+int selectAPTrackingMode(int trackMode);
+
+/**************************************************************************
+ Other Commands
+ **************************************************************************/
+ /* Ensures LX200 RA/DEC format is long */
+int checkLX200Format(void);
+/* Select a site from the LX200 controller */
+int selectSite(int siteNum);
+/* Select a catalog object */
+int selectCatalogObject(int catalog, int NNNN);
+/* Select a sub catalog */
+int selectSubCatalog(int catalog, int subCatalog);
+
+/**********************************************************************
+* BASIC
+**********************************************************************/
+
+int Connect(const char *device)
+{
+ fprintf(stderr, "Connecting to device %s\n", device);
+
+ if (openPort(device) < 0)
+ return -1;
+ else
+ return 0;
+}
+
+void Disconnect()
+{
+fprintf(stderr, "Disconnected.\n");
+close(fd);
+}
+
+int testTelescope()
+{
+ int i=0;
+ char ack[1] = { (char) 0x06 };
+ char MountAlign[64];
+ fprintf(stderr, "Testing telescope's connection...\n");
+
+ for (i=0; i < 2; i++)
+ {
+ write(fd, ack, 1);
+ read_ret = portRead(MountAlign, 1, LX200_TIMEOUT);
+ if (read_ret == 1)
+ return 0;
+ usleep(50000);
+ }
+
+ return -1;
+}
+
+int testAP()
+{
+ int i=0;
+ char currentDate[64];
+
+ fprintf(stderr, "Testing telescope's connection...\n");
+
+ /* We need to test if the telescope is responding
+ / We're going to request the calander date */
+ for (i=0; i < 2; i++)
+ {
+ if (!getCalenderDate(currentDate))
+ return 0;
+
+ usleep(50000);
+ }
+
+ return -1;
+
+}
+
+
+/**********************************************************************
+* GET
+**********************************************************************/
+
+char ACK()
+{
+ char ack[1] = { (char) 0x06 };
+ char MountAlign[2];
+
+ write_ret = write(fd, ack, 1);
+
+ if (write_ret < 0)
+ return -1;
+
+ read_ret = portRead(MountAlign, 1, LX200_TIMEOUT);
+
+ if (read_ret == 1)
+ return MountAlign[0];
+ else
+ return read_ret;
+
+}
+
+int getCommandSexa(double *value, const char * cmd)
+{
+ char tempString[16];
+
+ tcflush(fd, TCIFLUSH);
+
+ if (portWrite(cmd) < 0)
+ return -1;
+
+ if ( (read_ret = portRead(tempString, -1, LX200_TIMEOUT)) < 1)
+ return read_ret;
+
+ tempString[read_ret - 1] = '\0';
+
+ if (f_scansexa(tempString, value))
+ {
+ fprintf(stderr, "unable to process [%s]\n", tempString);
+ return -1;
+ }
+
+ return 0;
+}
+
+int getCommandString(char *data, const char* cmd)
+{
+ char * term;
+
+ if (portWrite(cmd) < 0)
+ return -1;
+
+ read_ret = portRead(data, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ term = strchr (data, '#');
+ if (term)
+ *term = '\0';
+
+ fprintf(stderr, "Requested data: %s\n", data);
+
+ return 0;
+}
+
+int getCalenderDate(char *date)
+{
+
+ int dd, mm, yy;
+ int err;
+
+ if ( (err = getCommandString(date, "#:GC#")) )
+ return err;
+
+ /* Meade format is MM/DD/YY */
+
+ read_ret = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy);
+ if (read_ret < 3)
+ return -1;
+
+ /* We need to have in in YYYY/MM/DD format */
+ sprintf(date, "20%02d/%02d/%02d", yy, mm, dd);
+
+ return (0);
+
+}
+
+int getTimeFormat(int *format)
+{
+ char tempString[16];
+ int tMode;
+
+ if (portWrite("#:Gc#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret-1] = '\0';
+
+ read_ret = sscanf(tempString, "(%d)", &tMode);
+
+ if (read_ret < 1)
+ return -1;
+ else
+ *format = tMode;
+
+ return 0;
+
+}
+
+/*int getUTCOffset()
+{
+ char tempString[4];
+ int offSet;
+
+ portWrite("#:GG#");
+
+ read_ret = portRead(tempString, 4);
+ if (read_ret)
+ return -1;
+
+ tempString[3] = '\0';
+
+ sscanf(tempString, "%d", &offSet);
+
+ fprintf(stderr, "UTC Offset: %d\n", offSet);
+
+ return offSet;
+}
+
+int getMaxElevationLimit()
+{
+ char tempString[16];
+ int limit;
+
+ portWrite("#:Go#");
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+ if (read_ret < 1)
+ return -1;
+
+ tempString[read_ret-1] = '\0';
+
+ sscanf(tempString, "%d", &limit);
+
+ fprintf(stderr, "Max elevation limit string is %s\n", tempString);
+
+ return limit;
+}
+
+int getMinElevationLimit()
+{
+ char tempString[16];
+ int limit;
+
+ portWrite("#:Gh#");
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+ if (read_ret < 1)
+ return -1;
+
+ tempString[read_ret-1] = '\0';
+
+ sscanf(tempString, "%d", &limit);
+
+ fprintf(stderr, "Min elevation limit string is %s\n", tempString);
+
+ return limit;
+
+}
+*/
+
+int getSiteName(char *siteName, int siteNum)
+{
+ char * term;
+
+ switch (siteNum)
+ {
+ case 1:
+ if (portWrite("#:GM#") < 0)
+ return -1;
+ break;
+ case 2:
+ if (portWrite("#:GN#") < 0)
+ return -1;
+ break;
+ case 3:
+ if (portWrite("#:GO#") < 0)
+ return -1;
+ break;
+ case 4:
+ if (portWrite("#:GP#") < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ read_ret = portRead(siteName, -1, LX200_TIMEOUT);
+ if (read_ret < 1)
+ return read_ret;
+
+ siteName[read_ret - 1] = '\0';
+
+ term = strchr (siteName, ' ');
+ if (term)
+ *term = '\0';
+
+ term = strchr (siteName, '<');
+ if (term)
+ strcpy(siteName, "unused site");
+
+ fprintf(stderr, "Requested site name: %s\n", siteName);
+
+ return 0;
+}
+
+int getSiteLatitude(int *dd, int *mm)
+{
+ char tempString[16];
+
+ if (portWrite("#:Gt#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret -1] = '\0';
+
+ if (sscanf (tempString, "%d%*c%d", dd, mm) < 2)
+ return -1;
+
+ fprintf(stderr, "Requested site latitude in String %s\n", tempString);
+ fprintf(stderr, "Requested site latitude %d:%d\n", *dd, *mm);
+
+ return 0;
+}
+
+int getSiteLongitude(int *ddd, int *mm)
+{
+ char tempString[16];
+
+ if (portWrite("#:Gg#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret -1] = '\0';
+
+ if (sscanf (tempString, "%d%*c%d", ddd, mm) < 2)
+ return -1;
+
+ fprintf(stderr, "Requested site longitude in String %s\n", tempString);
+ fprintf(stderr, "Requested site longitude %d:%d\n", *ddd, *mm);
+
+ return 0;
+}
+
+int getTrackFreq(double *value)
+{
+ float Freq;
+ char tempString[16];
+
+ if (portWrite("#:GT#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret] = '\0';
+
+ /*fprintf(stderr, "Telescope tracking freq str: %s\n", tempString);*/
+
+ if (sscanf(tempString, "%f#", &Freq) < 1)
+ return -1;
+
+ *value = (double) Freq;
+
+ /*fprintf(stderr, "Tracking frequency value is %f\n", Freq);*/
+
+ return 0;
+}
+
+int getNumberOfBars(int *value)
+{
+ char tempString[128];
+
+ if (portWrite("#:D#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 0)
+ return read_ret;
+
+ *value = read_ret -1;
+
+ return 0;
+}
+
+int getHomeSearchStatus(int *status)
+{
+ char tempString[16];
+
+ if (portWrite("#:h?#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, 1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[1] = '\0';
+
+ if (tempString[0] == '0')
+ *status = 0;
+ else if (tempString[0] == '1')
+ *status = 1;
+ else if (tempString[0] == '2')
+ *status = 1;
+
+ return 0;
+}
+
+int getOTATemp(double *value)
+{
+
+ char tempString[16];
+ float temp;
+
+ if (portWrite("#:fT#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret - 1] = '\0';
+
+ if (sscanf(tempString, "%f", &temp) < 1)
+ return -1;
+
+ *value = (double) temp;
+
+ return 0;
+
+}
+
+int updateSkyCommanderCoord(double *ra, double *dec)
+{
+ char coords[16];
+ char CR[1] = { (char) 0x0D };
+ float RA=0.0, DEC=0.0;
+
+ write(fd, CR, 1);
+
+ read_ret = portRead(coords, 16, LX200_TIMEOUT);
+
+ read_ret = sscanf(coords, " %g %g", &RA, &DEC);
+
+ if (read_ret < 2)
+ {
+ fprintf(stderr, "Error in Sky commander number format [%s], exiting.\n", coords);
+ return -1;
+ }
+
+ *ra = RA;
+ *dec = DEC;
+
+ return 0;
+
+}
+
+
+/**********************************************************************
+* SET
+**********************************************************************/
+
+int setStandardProcedure(char * data)
+{
+ char boolRet[2];
+
+ if (portWrite(data) < 0)
+ return -1;
+
+ read_ret = portRead(boolRet, 1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ if (boolRet[0] == '0')
+ {
+ fprintf(stderr, "%s Failed.\n", data);
+ return -1;
+ }
+
+ fprintf(stderr, "%s Successful\n", data);
+ return 0;
+
+
+}
+
+int setCommandInt(int data, const char *cmd)
+{
+
+ char tempString[16];
+
+ snprintf(tempString, sizeof( tempString ), "%s%d#", cmd, data);
+
+ if (portWrite(tempString) < 0)
+ return -1;
+
+ return 0;
+}
+
+int setMinElevationLimit(int min)
+{
+ char tempString[16];
+
+ snprintf(tempString, sizeof( tempString ), "#:Sh%02d#", min);
+
+ return (setStandardProcedure(tempString));
+}
+
+int setMaxElevationLimit(int max)
+{
+ char tempString[16];
+
+ snprintf(tempString, sizeof( tempString ), "#:So%02d*#", max);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+int setMaxSlewRate(int slewRate)
+{
+
+ char tempString[16];
+
+ if (slewRate < 2 || slewRate > 8)
+ return -1;
+
+ snprintf(tempString, sizeof( tempString ), "#:Sw%d#", slewRate);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+
+int setObjectRA(double ra)
+{
+
+ int h, m, s;
+ char tempString[16];
+
+ getSexComponents(ra, &h, &m, &s);
+
+ snprintf(tempString, sizeof( tempString ), "#:Sr %02d:%02d:%02d#", h, m, s);
+ IDLog("Set Object RA String %s\n", tempString);
+ return (setStandardProcedure(tempString));
+}
+
+
+int setObjectDEC(double dec)
+{
+ int d, m, s;
+ char tempString[16];
+
+ getSexComponents(dec, &d, &m, &s);
+
+ /* case with negative zero */
+ if (!d && dec < 0)
+ snprintf(tempString, sizeof( tempString ), "#:Sd -%02d:%02d:%02d#", d, m, s);
+ else
+ snprintf(tempString, sizeof( tempString ), "#:Sd %+03d:%02d:%02d#", d, m, s);
+
+ IDLog("Set Object DEC String %s\n", tempString);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+int setCommandXYZ(int x, int y, int z, const char *cmd)
+{
+ char tempString[16];
+
+ snprintf(tempString, sizeof( tempString ), "%s %02d:%02d:%02d#", cmd, x, y, z);
+
+ return (setStandardProcedure(tempString));
+}
+
+int setAlignmentMode(unsigned int alignMode)
+{
+ fprintf(stderr , "Set alignment mode %d\n", alignMode);
+
+ switch (alignMode)
+ {
+ case LX200_ALIGN_POLAR:
+ if (portWrite("#:AP#") < 0)
+ return -1;
+ break;
+ case LX200_ALIGN_ALTAZ:
+ if (portWrite("#:AA#") < 0)
+ return -1;
+ break;
+ case LX200_ALIGN_LAND:
+ if (portWrite("#:AL#") < 0)
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+int setCalenderDate(int dd, int mm, int yy)
+{
+ char tempString[32];
+ char dumpPlanetaryUpdateString[64];
+ char boolRet[2];
+ yy = yy % 100;
+
+ snprintf(tempString, sizeof( tempString ), "#:SC %02d/%02d/%02d#", mm, dd, yy);
+
+ if (portWrite(tempString) < 0)
+ return -1;
+
+ read_ret = portRead(boolRet, 1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ boolRet[1] = '\0';
+
+ if (boolRet[0] == '0')
+ return -1;
+
+ /* Read dumped data */
+ portRead(dumpPlanetaryUpdateString, -1, LX200_TIMEOUT);
+ portRead(dumpPlanetaryUpdateString, -1, 5);
+
+ return 0;
+}
+
+int setUTCOffset(double hours)
+{
+ char tempString[16];
+
+ /*TODO add fractions*/
+ snprintf(tempString, sizeof( tempString ), "#:SG %+03d#", (int) hours);
+
+ fprintf(stderr, "UTC string is %s\n", tempString);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+int setSiteLongitude(double Long)
+{
+ int d, m, s;
+ char tempString[32];
+
+ getSexComponents(Long, &d, &m, &s);
+
+ snprintf(tempString, sizeof( tempString ), "#:Sg%03d:%02d#", d, m);
+
+ return (setStandardProcedure(tempString));
+}
+
+int setSiteLatitude(double Lat)
+{
+ int d, m, s;
+ char tempString[32];
+
+ getSexComponents(Lat, &d, &m, &s);
+
+ snprintf(tempString, sizeof( tempString ), "#:St%+03d:%02d:%02d#", d, m, s);
+
+ return (setStandardProcedure(tempString));
+}
+
+int setObjAz(double az)
+{
+ int d,m,s;
+ char tempString[16];
+
+ getSexComponents(az, &d, &m, &s);
+
+ snprintf(tempString, sizeof( tempString ), "#:Sz%03d:%02d#", d, m);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+int setObjAlt(double alt)
+{
+ int d, m, s;
+ char tempString[16];
+
+ getSexComponents(alt, &d, &m, &s);
+
+ snprintf(tempString, sizeof( tempString ), "#:Sa%+02d*%02d#", d, m);
+
+ return (setStandardProcedure(tempString));
+}
+
+
+int setSiteName(char * siteName, int siteNum)
+{
+
+ char tempString[16];
+
+ switch (siteNum)
+ {
+ case 1:
+ snprintf(tempString, sizeof( tempString ), "#:SM %s#", siteName);
+ break;
+ case 2:
+ snprintf(tempString, sizeof( tempString ), "#:SN %s#", siteName);
+ break;
+ case 3:
+ snprintf(tempString, sizeof( tempString ), "#:SO %s#", siteName);
+ break;
+ case 4:
+ snprintf(tempString, sizeof( tempString ), "#:SP %s#", siteName);
+ break;
+ default:
+ return -1;
+ }
+
+ return (setStandardProcedure(tempString));
+}
+
+int setSlewMode(int slewMode)
+{
+
+ switch (slewMode)
+ {
+ case LX200_SLEW_MAX:
+ if (portWrite("#:RS#") < 0)
+ return -1;
+ break;
+ case LX200_SLEW_FIND:
+ if (portWrite("#:RM#") < 0)
+ return -1;
+ break;
+ case LX200_SLEW_CENTER:
+ if (portWrite("#:RC#") < 0)
+ return -1;
+ break;
+ case LX200_SLEW_GUIDE:
+ if (portWrite("#:RG#") < 0)
+ return -1;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+
+}
+
+int setFocuserMotion(int motionType)
+{
+
+ switch (motionType)
+ {
+ case LX200_FOCUSIN:
+ if (portWrite("#:F+#") < 0)
+ return -1;
+ break;
+ case LX200_FOCUSOUT:
+ if (portWrite("#:F-#") < 0)
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+int setFocuserSpeedMode (int speedMode)
+{
+
+ switch (speedMode)
+ {
+ case LX200_HALTFOCUS:
+ if (portWrite("#:FQ#") < 0)
+ return -1;
+ break;
+ case LX200_FOCUSSLOW:
+ if (portWrite("#:FS#") < 0)
+ return -1;
+ break;
+ case LX200_FOCUSMEDIUM:
+ if (portWrite("#:F3#") < 0)
+ return -1;
+ break;
+ case LX200_FOCUSFAST:
+ if (portWrite("#:FF#") < 0)
+ return -1;
+ break;
+ }
+
+ return 0;
+
+}
+
+int setTrackFreq(double trackF)
+{
+ char tempString[16];
+
+ snprintf(tempString, sizeof( tempString ), "#:ST %04.1f#", trackF);
+
+ return (setStandardProcedure(tempString));
+
+}
+
+/**********************************************************************
+* Misc
+*********************************************************************/
+
+int Slew()
+{
+ char slewNum[2];
+ char errorMsg[128];
+
+ if (portWrite("#:MS#") < 0)
+ return -1;
+
+ read_ret = portRead(slewNum, 1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ slewNum[1] = '\0';
+
+ if (slewNum[0] == '0')
+ return 0;
+
+ read_ret = portRead(errorMsg, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ if (slewNum[0] == '1')
+ return 1;
+ else return 2;
+
+}
+
+int MoveTo(int direction)
+{
+
+ switch (direction)
+ {
+ case LX200_NORTH:
+ portWrite("#:Mn#");
+ break;
+ case LX200_WEST:
+ portWrite("#:Mw#");
+ break;
+ case LX200_EAST:
+ portWrite("#:Me#");
+ break;
+ case LX200_SOUTH:
+ portWrite("#:Ms#");
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int HaltMovement(int direction)
+{
+
+switch (direction)
+ {
+ case LX200_NORTH:
+ if (portWrite("#:Qn#") < 0)
+ return -1;
+ break;
+ case LX200_WEST:
+ if (portWrite("#:Qw#") < 0)
+ return -1;
+ break;
+ case LX200_EAST:
+ if (portWrite("#:Qe#") < 0)
+ return -1;
+ break;
+ case LX200_SOUTH:
+ if (portWrite("#:Qs#") < 0)
+ return -1;
+ break;
+ case LX200_ALL:
+ if (portWrite("#:Q#") < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+
+}
+
+int abortSlew()
+{
+ if (portWrite("#:Q#") < 0)
+ return -1;
+
+ return 0;
+}
+
+int Sync(char *matchedObject)
+{
+ portWrite("#:CM#");
+
+ read_ret = portRead(matchedObject, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ matchedObject[read_ret-1] = '\0';
+
+ /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
+ usleep(10000);
+
+ tcflush(fd, TCIFLUSH);
+
+ return 0;
+}
+
+int selectSite(int siteNum)
+{
+
+ switch (siteNum)
+ {
+ case 1:
+ if (portWrite("#:W1#") < 0)
+ return -1;
+ break;
+ case 2:
+ if (portWrite("#:W2#") < 0)
+ return -1;
+ break;
+ case 3:
+ if (portWrite("#:W3#") < 0)
+ return -1;
+ break;
+ case 4:
+ if (portWrite("#:W4#") < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+
+}
+
+int selectCatalogObject(int catalog, int NNNN)
+{
+ char tempString[16];
+
+ switch (catalog)
+ {
+ case LX200_STAR_C:
+ snprintf(tempString, sizeof( tempString ), "#:LS%d#", NNNN);
+ break;
+ case LX200_DEEPSKY_C:
+ snprintf(tempString, sizeof( tempString ), "#:LC%d#", NNNN);
+ break;
+ case LX200_MESSIER_C:
+ snprintf(tempString, sizeof( tempString ), "#:LM%d#", NNNN);
+ break;
+ default:
+ return -1;
+ }
+
+ if (portWrite(tempString) < 0)
+ return -1;
+
+ return 0;
+}
+
+int selectSubCatalog(int catalog, int subCatalog)
+{
+ char tempString[16];
+ switch (catalog)
+ {
+ case LX200_STAR_C:
+ snprintf(tempString, sizeof( tempString ), "#:LsD%d#", subCatalog);
+ break;
+ case LX200_DEEPSKY_C:
+ snprintf(tempString, sizeof( tempString ), "#:LoD%d#", subCatalog);
+ break;
+ case LX200_MESSIER_C:
+ return 1;
+ default:
+ return 0;
+ }
+
+ return (setStandardProcedure(tempString));
+}
+
+int checkLX200Format()
+{
+
+ char tempString[16];
+
+ if (portWrite("#:GR#") < 0)
+ return -1;
+
+ read_ret = portRead(tempString, -1, LX200_TIMEOUT);
+
+ if (read_ret < 1)
+ return read_ret;
+
+ tempString[read_ret - 1] = '\0';
+
+ /* Short */
+ if (tempString[5] == '.')
+ if (portWrite("#:U#") < 0)
+ return -1;
+
+ return 0;
+}
+
+int selectTrackingMode(int trackMode)
+{
+
+ switch (trackMode)
+ {
+ case LX200_TRACK_DEFAULT:
+ fprintf(stderr, "Setting tracking mode to sidereal.\n");
+ if (portWrite("#:TQ#") < 0)
+ return -1;
+ break;
+ case LX200_TRACK_LUNAR:
+ fprintf(stderr, "Setting tracking mode to LUNAR.\n");
+ if (portWrite("#:TL#") < 0)
+ return -1;
+ break;
+ case LX200_TRACK_MANUAL:
+ fprintf(stderr, "Setting tracking mode to CUSTOM.\n");
+ if (portWrite("#:TM#") < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+
+}
+
+int selectAPTrackingMode(int trackMode)
+{
+ switch (trackMode)
+ {
+ /* Lunar */
+ case 0:
+ fprintf(stderr, "Setting tracking mode to lunar.\n");
+ if (portWrite("#:RT0#") < 0)
+ return -1;
+ break;
+
+ /* Solar */
+ case 1:
+ fprintf(stderr, "Setting tracking mode to solar.\n");
+ if (portWrite("#:RT1#") < 0)
+ return -1;
+ break;
+
+ /* Sidereal */
+ case 2:
+ fprintf(stderr, "Setting tracking mode to sidereal.\n");
+ if (portWrite("#:RT2#") < 0)
+ return -1;
+ break;
+
+ /* Zero */
+ case 3:
+ fprintf(stderr, "Setting tracking mode to zero.\n");
+ if (portWrite("#:RT9#") < 0)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+
+}
+
+
+/**********************************************************************
+* Comm
+**********************************************************************/
+
+int openPort(const char *portID)
+{
+ struct termios ttyOptions;
+
+ if ( (fd = open(portID, O_RDWR)) == -1)
+ return -1;
+
+ memset(&ttyOptions, 0, sizeof(ttyOptions));
+ tcgetattr(fd, &ttyOptions);
+
+ /* Control options
+ charecter size */
+ ttyOptions.c_cflag &= ~CSIZE;
+ /* 8 bit, enable read */
+ ttyOptions.c_cflag |= CREAD | CLOCAL | CS8;
+ /* no parity */
+ ttyOptions.c_cflag &= ~PARENB;
+
+ /* set baud rate */
+ cfsetispeed(&ttyOptions, B9600);
+ cfsetospeed(&ttyOptions, B9600);
+
+ /* set input/output flags */
+ ttyOptions.c_iflag = IGNBRK;
+ /* no software flow control */
+ ttyOptions.c_iflag &= ~(IXON|IXOFF|IXANY);
+
+ /* Read at least one byte */
+ ttyOptions.c_cc[VMIN] = 1;
+ ttyOptions.c_cc[VTIME] = 5;
+
+ /* Misc. */
+ ttyOptions.c_lflag = 0;
+ ttyOptions.c_oflag = 0;
+
+ /* set attributes */
+ tcsetattr(fd, TCSANOW, &ttyOptions);
+
+ /* flush the channel */
+ tcflush(fd, TCIOFLUSH);
+ return (fd);
+}
+
+int portWrite(const char * buf)
+{
+ int nbytes, totalBytesWritten;
+ int bytesWritten = 0;
+
+ nbytes = totalBytesWritten = strlen(buf);
+
+ while (nbytes > 0)
+ {
+
+ bytesWritten = write(fd, buf, nbytes);
+
+ if (bytesWritten < 0)
+ return -1;
+
+ buf += bytesWritten;
+ nbytes -= bytesWritten;
+ }
+
+ /* Returns the # of bytes written */
+ return (totalBytesWritten);
+}
+
+int portRead(char *buf, int nbytes, int timeout)
+{
+
+int bytesRead = 0;
+int totalBytesRead = 0;
+int err;
+
+ /* Loop until encountring the '#' char */
+ if (nbytes == -1)
+ {
+ for (;;)
+ {
+ if ( (err = LX200readOut(timeout)) )
+ return err;
+
+ bytesRead = read(fd, buf, 1);
+
+ if (bytesRead < 0 )
+ return -1;
+
+ if (bytesRead)
+ totalBytesRead++;
+
+ if (*buf == '#')
+ return totalBytesRead;
+
+ buf += bytesRead;
+ }
+ }
+
+ while (nbytes > 0)
+ {
+ if ( (err = LX200readOut(timeout)) )
+ return err;
+
+ bytesRead = read(fd, buf, nbytes);
+
+ if (bytesRead < 0 )
+ return -1;
+
+ buf += bytesRead;
+ totalBytesRead++;
+ nbytes -= bytesRead;
+ }
+
+ return totalBytesRead;
+}
+
+int LX200readOut(int timeout)
+{
+ struct timeval tv;
+ fd_set readout;
+ int retval;
+
+ FD_ZERO(&readout);
+ FD_SET(fd, &readout);
+
+ /* wait for 'timeout' seconds */
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ /* Wait till we have a change in the fd status */
+ retval = select (fd+1, &readout, NULL, NULL, &tv);
+
+ /* Return 0 on successful fd change */
+ if (retval > 0)
+ return 0;
+ /* Return -1 due to an error */
+ else if (retval == -1)
+ return retval;
+ /* Return -2 if time expires before anything interesting happens */
+ else
+ return -2;
+
+}
+