• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kstars

lx200generic.cpp

Go to the documentation of this file.
00001 #if 0
00002     LX200 Generic
00003     Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Lesser General Public
00007     License as published by the Free Software Foundation; either
00008     version 2.1 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public
00016     License along with this library; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 #endif
00020 
00021 #include "config.h"
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <stdarg.h>
00027 #include <math.h>
00028 #include <unistd.h>
00029 #include <time.h>
00030 
00031 #include "indicom.h"
00032 #include "lx200driver.h"
00033 #include "lx200gps.h"
00034 #include "lx200classic.h"
00035 
00036 /*
00037 ** Return the timezone offset in hours (as a double, so fractional
00038 ** hours are possible, for instance in Newfoundland). Also sets
00039 ** daylight on non-Linux systems to record whether DST is in effect.
00040 */
00041 
00042 
00043 #if !(TIMEZONE_IS_INT)
00044 static int daylight = 0;
00045 #endif
00046 
00047 static inline double timezoneOffset()
00048 {
00049 /* 
00050 ** In Linux, there's a timezone variable that holds the timezone offset;
00051 ** Otherwise, we need to make a little detour. The directions of the offset
00052 ** are different: CET is -3600 in Linux and +3600 elsewhere.
00053 */
00054 #if TIMEZONE_IS_INT
00055   return timezone / (60 * 60);
00056 #else
00057   time_t now;
00058   struct tm *tm;
00059   now = time(NULL);
00060   tm = localtime(&now);
00061   daylight = tm->tm_isdst;
00062   return -(tm->tm_gmtoff) / (60 * 60);
00063 #endif
00064 }
00065 
00066 LX200Generic *telescope = NULL;
00067 int MaxReticleFlashRate = 3;
00068 
00069 /* There is _one_ binary for all LX200 drivers, but each binary is renamed
00070 ** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
00071 ** fetch from std args the binary name and ISInit will create the apporpiate
00072 ** device afterwards. If the binary name does not match any known devices,
00073 ** we simply create a generic device
00074 */
00075 extern char* me;
00076 
00077 #define COMM_GROUP  "Communication"
00078 #define BASIC_GROUP "Main Control"
00079 #define MOVE_GROUP  "Movement Control"
00080 #define DATETIME_GROUP  "Date/Time"
00081 #define SITE_GROUP  "Site Management"
00082 #define FOCUS_GROUP "Focus Control"
00083 
00084 #define RA_THRESHOLD    0.01
00085 #define DEC_THRESHOLD   0.05
00086 #define LX200_SLEW  0
00087 #define LX200_TRACK 1
00088 #define LX200_SYNC  2
00089 #define LX200_PARK  3
00090 
00091 static void ISPoll(void *);
00092 static void retryConnection(void *);
00093 
00094 /*INDI controls */
00095 static ISwitch PowerS[]          = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
00096 static ISwitch AlignmentS []     = {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}};
00097 static ISwitch SitesS[]          = {{"Site 1", "", ISS_ON, 0, 0}, {"Site 2", "", ISS_OFF, 0, 0},  {"Site 3", "", ISS_OFF, 0, 0},  {"Site 4", "", ISS_OFF, 0 ,0}};
00098 static ISwitch SlewModeS[]       = {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}};
00099 static ISwitch OnCoordSetS[]     = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"TRACK", "Track", ISS_OFF, 0, 0}, {"SYNC", "Sync", ISS_OFF, 0 , 0}};
00100 static ISwitch TrackModeS[]      = {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}};
00101 static ISwitch abortSlewS[]      = {{"ABORT", "Abort", ISS_OFF, 0, 0 }};
00102 static ISwitch ParkS[]       = { {"PARK", "Park", ISS_OFF, 0, 0} };
00103 
00104 static ISwitch MovementS[]       = {{"N", "North", ISS_OFF, 0, 0}, {"W", "West", ISS_OFF, 0, 0}, {"E", "East", ISS_OFF, 0, 0}, {"S", "South", ISS_OFF, 0, 0}};
00105 
00106 static INumber  FocusSpeedN[]    = {{"SPEED", "Speed", "%0.f", 0., 3., 1., 0.}};
00107 static ISwitch  FocusMotionS[]   = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}};
00108 static INumber  FocusTimerN[]    = { {"TIMER", "Timer (s)", "%10.6m", 0., 120., 1., 0., 0, 0, 0 }};
00109 
00110 static INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0};
00111 
00112 /* equatorial position */
00113 INumber eq[] = {
00114     {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},
00115     {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
00116 };
00117 //TODO decide appropiate TIME_OUT
00118 // N.B. No Static identifier as it is needed for external linkage
00119 INumberVectorProperty eqNum = {
00120     mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE,
00121     eq, NARRAY(eq), "", 0};
00122 
00123 /* Fundamental group */
00124 ISwitchVectorProperty PowerSP       = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
00125 static IText PortT[]            = {{"PORT", "Port", 0, 0, 0, 0}};
00126 static ITextVectorProperty Port     = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
00127 
00128 /* Basic data group */
00129 static ISwitchVectorProperty AlignmentSw    = { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0};
00130 
00131 /* Movement group */
00132 static ISwitchVectorProperty OnCoordSetSw    = { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
00133 
00134 static ISwitchVectorProperty abortSlewSw     = { mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, abortSlewS, NARRAY(abortSlewS), "", 0};
00135 
00136 ISwitchVectorProperty   ParkSP = {mydev, "PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0 };
00137 
00138 static ISwitchVectorProperty SlewModeSw      = { mydev, "Slew rate", "", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
00139 
00140 static ISwitchVectorProperty TrackModeSw  = { mydev, "Tracking Mode", "", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0};
00141 
00142 static INumber TrackFreq[]  = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}};
00143 
00144 static INumberVectorProperty TrackingFreq= { mydev, "Tracking Frequency", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, TrackFreq, NARRAY(TrackFreq), "", 0};
00145 
00146 static ISwitchVectorProperty MovementSw      = { mydev, "MOVEMENT", "Move toward", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementS, NARRAY(MovementS), "", 0};
00147 
00148 // Focus Control
00149 static INumberVectorProperty    FocusSpeedNP  = {mydev, "FOCUS_SPEED", "Speed", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusSpeedN, NARRAY(FocusSpeedN), "", 0};
00150 
00151 static ISwitchVectorProperty    FocusMotionSw = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0};
00152 
00153 /* Data & Time */
00154 static IText UTC[] = {{"UTC", "UTC", 0, 0, 0, 0}};
00155 ITextVectorProperty Time = { mydev, "TIME", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTC, NARRAY(UTC), "", 0};
00156 static INumber STime[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}};
00157 INumberVectorProperty SDTime = { mydev, "SDTIME", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, STime, NARRAY(STime), "", 0};
00158 
00159 
00160 /* Site managment */
00161 static ISwitchVectorProperty SitesSw  = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0};
00162 /* geographic location */
00163 static INumber geo[] = {
00164     {"LAT",  "Lat.  D:M:S +N", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
00165     {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
00166 };
00167 static INumberVectorProperty geoNum = {
00168     mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE,
00169     geo, NARRAY(geo), "", 0};
00170 static IText   SiteNameT[] = {{"SiteName", "", 0, 0, 0, 0}};
00171 static ITextVectorProperty SiteName = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0};
00172 
00173 void changeLX200GenericDeviceName(const char * newName)
00174 {
00175   strcpy(PowerSP.device , newName);
00176   strcpy(Port.device , newName);
00177   strcpy(AlignmentSw.device, newName);
00178 
00179   // BASIC_GROUP
00180   strcpy(eqNum.device, newName);
00181   strcpy(OnCoordSetSw.device , newName );
00182   strcpy(abortSlewSw.device , newName );
00183   strcpy(ParkSP.device, newName);
00184 
00185   // MOVE_GROUP
00186   strcpy(SlewModeSw.device , newName );
00187   strcpy(TrackModeSw.device , newName );
00188   strcpy(TrackingFreq.device , newName );
00189   strcpy(MovementSw.device , newName );
00190 
00191   // FOCUS_GROUP
00192   strcpy(FocusSpeedNP.device , newName );
00193   strcpy(FocusMotionSw.device , newName );
00194   strcpy(FocusTimerNP.device, newName);
00195 
00196   // DATETIME_GROUP
00197   strcpy(Time.device , newName );
00198   strcpy(SDTime.device , newName );
00199 
00200   // SITE_GROUP
00201   strcpy(SitesSw.device , newName );
00202   strcpy(SiteName.device , newName );
00203   strcpy(geoNum.device , newName );
00204   
00205 }
00206 
00207 void changeAllDeviceNames(const char *newName)
00208 {
00209   changeLX200GenericDeviceName(newName);
00210   changeLX200AutostarDeviceName(newName);
00211   changeLX200_16DeviceName(newName);
00212   changeLX200ClassicDeviceName(newName);
00213   changeLX200GPSDeviceName(newName);
00214 }
00215 
00216 
00217 /* send client definitions of all properties */
00218 void ISInit()
00219 {
00220   static int isInit=0;
00221 
00222  if (isInit)
00223   return;
00224 
00225  isInit = 1;
00226  
00227   PortT[0].text = strcpy(new char[32], "/dev/ttyS0");
00228   UTC[0].text   = strcpy(new char[32], "YYYY-MM-DDTHH:MM:SS");
00229   
00230   if (strstr(me, "lx200classic"))
00231   {
00232      fprintf(stderr , "initilizaing from LX200 classic device...\n");
00233      // 1. mydev = device_name
00234      changeAllDeviceNames("LX200 Classic");
00235      // 2. device = sub_class
00236      telescope = new LX200Classic();
00237      telescope->setCurrentDeviceName("LX200 Classic");
00238 
00239      MaxReticleFlashRate = 3;
00240   }
00241 
00242   else if (strstr(me, "lx200gps"))
00243   {
00244      fprintf(stderr , "initilizaing from LX200 GPS device...\n");
00245      // 1. mydev = device_name
00246      changeAllDeviceNames("LX200 GPS");
00247      // 2. device = sub_class
00248      telescope = new LX200GPS();
00249      telescope->setCurrentDeviceName("LX200 GPS");
00250 
00251      MaxReticleFlashRate = 9;
00252   }
00253   else if (strstr(me, "lx200_16"))
00254   {
00255 
00256     IDLog("Initilizaing from LX200 16 device...\n");
00257     // 1. mydev = device_name
00258     changeAllDeviceNames("LX200 16");
00259     // 2. device = sub_class
00260    telescope = new LX200_16();
00261    telescope->setCurrentDeviceName("LX200 16");
00262 
00263    MaxReticleFlashRate = 3;
00264  }
00265  else if (strstr(me, "lx200autostar"))
00266  {
00267    fprintf(stderr , "initilizaing from autostar device...\n");
00268   
00269    // 1. change device name
00270    changeAllDeviceNames("LX200 Autostar");
00271    // 2. device = sub_class
00272    telescope = new LX200Autostar();
00273    telescope->setCurrentDeviceName("LX200 Autostar");
00274 
00275    MaxReticleFlashRate = 9;
00276  }
00277  // be nice and give them a generic device
00278  else
00279  {
00280   telescope = new LX200Generic();
00281   telescope->setCurrentDeviceName("LX200 Generic");
00282  }
00283 
00284 }
00285 
00286 void ISGetProperties (const char *dev)
00287 { ISInit(); telescope->ISGetProperties(dev); IEAddTimer (POLLMS, ISPoll, NULL);}
00288 void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
00289 { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
00290 void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
00291 { ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
00292 void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
00293 { ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
00294 void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
00295 void ISNewBLOB (const char */*dev*/, const char */*name*/, int */*sizes[]*/, char **/*blobs[]*/, char **/*formats[]*/, char **/*names[]*/, int /*n*/)
00296 {}
00297 
00298 /**************************************************
00299 *** LX200 Generic Implementation
00300 ***************************************************/
00301 
00302 LX200Generic::LX200Generic()
00303 {
00304    struct tm *utp;
00305    time_t t;
00306    time (&t);
00307    utp = gmtime (&t);
00308    
00309    currentSiteNum = 1;
00310    trackingMode   = LX200_TRACK_DEFAULT;
00311    lastSet        = -1;
00312    fault          = false;
00313    simulation     = false;
00314    targetRA       = 0;
00315    targetDEC      = 0;
00316    currentRA      = 0;
00317    currentDEC     = 0;
00318    currentSet     = 0;
00319    UTCOffset      = 0;
00320    lastMove[0] = lastMove[1] = lastMove[2] = lastMove[3] = 0;
00321 
00322    localTM = new tm;
00323    
00324    utp->tm_mon  += 1;
00325    utp->tm_year += 1900;
00326    JD = UTtoJD(utp);
00327    
00328    IDLog("Julian Day is %g\n", JD);
00329    
00330    // Children call parent routines, this is the default
00331    IDLog("initilizaing from generic LX200 device...\n");
00332    IDLog("INDI Version: 2004-02-17\n");
00333  
00334    //enableSimulation(true);  
00335 }
00336 
00337 void LX200Generic::setCurrentDeviceName(const char * devName)
00338 {
00339   strcpy(thisDevice, devName);
00340 
00341 }
00342 
00343 void LX200Generic::ISGetProperties(const char *dev)
00344 {
00345 
00346  if (dev && strcmp (thisDevice, dev))
00347     return;
00348 
00349   // COMM_GROUP
00350   IDDefSwitch (&PowerSP, NULL);
00351   IDDefText   (&Port, NULL);
00352   IDDefSwitch (&AlignmentSw, NULL);
00353 
00354   // BASIC_GROUP
00355   IDDefNumber (&eqNum, NULL);
00356   IDDefSwitch (&OnCoordSetSw, NULL);
00357   IDDefSwitch (&abortSlewSw, NULL);
00358   IDDefSwitch (&ParkSP, NULL);
00359 
00360   // MOVE_GROUP
00361   IDDefNumber (&TrackingFreq, NULL);
00362   IDDefSwitch (&SlewModeSw, NULL);
00363   IDDefSwitch (&TrackModeSw, NULL);
00364   IDDefSwitch (&MovementSw, NULL);
00365 
00366   // FOCUS_GROUP
00367   IDDefNumber(&FocusSpeedNP, NULL);
00368   IDDefSwitch(&FocusMotionSw, NULL);
00369   IDDefNumber(&FocusTimerNP, NULL);
00370 
00371   // DATETIME_GROUP
00372   IDDefText   (&Time, NULL);
00373   IDDefNumber (&SDTime, NULL);
00374 
00375   // SITE_GROUP
00376   IDDefSwitch (&SitesSw, NULL);
00377   IDDefText   (&SiteName, NULL);
00378   IDDefNumber (&geoNum, NULL);
00379   
00380   /* Send the basic data to the new client if the previous client(s) are already connected. */      
00381    if (PowerSP.s == IPS_OK)
00382        getBasicData();
00383 
00384 }
00385 
00386 void LX200Generic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
00387 {
00388     int err;
00389     struct tm *ltp = new tm;
00390     struct tm utm;
00391     time_t ltime;
00392     time (&ltime);
00393     localtime_r (&ltime, ltp);
00394     IText *tp;
00395 
00396     // ignore if not ours //
00397     if (strcmp (dev, thisDevice))
00398         return;
00399 
00400     // suppress warning
00401     n=n;
00402 
00403     if (!strcmp(name, Port.name) )
00404     {
00405       Port.s = IPS_OK;
00406       tp = IUFindText( &Port, names[0] );
00407       if (!tp)
00408        return;
00409 
00410       tp->text = new char[strlen(texts[0])+1];
00411       strcpy(tp->text, texts[0]);
00412       IDSetText (&Port, NULL);
00413       return;
00414     }
00415 
00416     if (!strcmp (name, SiteName.name) )
00417     {
00418       if (checkPower(&SiteName))
00419        return;
00420 
00421       if ( ( err = setSiteName(texts[0], currentSiteNum) < 0) )
00422       {
00423          handleError(&SiteName, err, "Setting site name");
00424          return;
00425       }
00426          SiteName.s = IPS_OK;
00427          tp = IUFindText(&SiteName, names[0]);
00428          tp->text = new char[strlen(texts[0])+1];
00429          strcpy(tp->text, texts[0]);
00430          IDSetText(&SiteName , "Site name updated");
00431          return;
00432        }
00433 
00434        if (!strcmp (name, Time.name))
00435        {
00436       if (checkPower(&Time))
00437        return;
00438       
00439       if (extractISOTime(texts[0], &utm) < 0)
00440       {
00441         Time.s = IPS_IDLE;
00442         IDSetText(&Time , "Time invalid");
00443         return;
00444       }
00445         ltp->tm_mon  += 1;
00446         ltp->tm_year += 1900;
00447 
00448             
00449                 /*dayDiff = utm.tm_mday - ltp->tm_mday;
00450         if (dayDiff == 0)
00451            UTCOffset = (ltp->tm_hour - utm.tm_hour);  
00452         else if (dayDiff > 0)
00453            UTCOffset = ltp->tm_hour - utm.tm_hour - 24;
00454         else UTCOffset = ltp->tm_hour - utm.tm_hour + 24;*/
00455         tzset();
00456         
00457         UTCOffset = timezoneOffset();
00458         
00459         IDLog("local time is %02d:%02d:%02d\nUTCOffset: %g\n", ltp->tm_hour, ltp->tm_min, ltp->tm_sec, UTCOffset);
00460         
00461         getSDTime(&STime[0].value);
00462         IDSetNumber(&SDTime, NULL);
00463         
00464         if ( ( err = setUTCOffset(UTCOffset) < 0) )
00465         {
00466             Time.s = IPS_IDLE;
00467             IDSetText( &Time , "Setting UTC Offset failed.");
00468         return;
00469         }
00470         
00471         if ( ( err = setLocalTime(ltp->tm_hour, ltp->tm_min, ltp->tm_sec) < 0) )
00472         {
00473               handleError(&Time, err, "Setting local time");
00474               return;
00475         }
00476 
00477         tp = IUFindText(&Time, names[0]);
00478         if (!tp)
00479          return;
00480         tp->text = new char[strlen(texts[0])+1];
00481             strcpy(tp->text, texts[0]);
00482         Time.s = IPS_OK;
00483 
00484         // update JD
00485                 JD = UTtoJD(&utm);
00486 
00487                 utm.tm_mon  += 1;
00488         utm.tm_year += 1900;
00489 
00490         IDLog("New JD is %f\n", (float) JD);
00491 
00492         if ((localTM->tm_mday == ltp->tm_mday ) && (localTM->tm_mon == ltp->tm_mon) &&
00493             (localTM->tm_year == ltp->tm_year))
00494         {
00495           IDSetText(&Time , "Time updated to %s", texts[0]);
00496           return;
00497         }
00498 
00499         localTM = ltp;
00500         
00501         if (!strcmp(dev, "LX200 GPS"))
00502         {
00503             if ( ( err = setCalenderDate(utm.tm_mday, utm.tm_mon, utm.tm_year) < 0) )
00504             {
00505                 handleError(&Time, err, "Setting UTC date.");
00506                 return;
00507             }
00508         }
00509         else
00510         {
00511             if ( ( err = setCalenderDate(ltp->tm_mday, ltp->tm_mon, ltp->tm_year) < 0) )
00512             {
00513                 handleError(&Time, err, "Setting local date.");
00514                 return;
00515             }
00516         }
00517         
00518         IDSetText(&Time , "Date changed, updating planetary data...");
00519     }
00520 }
00521 
00522 
00523 void LX200Generic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
00524 {
00525     int h =0, m =0, s=0, err;
00526     double newRA =0, newDEC =0;
00527     
00528     // ignore if not ours //
00529     if (strcmp (dev, thisDevice))
00530         return;
00531 
00532     if (!strcmp (name, eqNum.name))
00533     {
00534       int i=0, nset=0;
00535 
00536       if (checkPower(&eqNum))
00537        return;
00538 
00539         for (nset = i = 0; i < n; i++)
00540         {
00541         INumber *eqp = IUFindNumber (&eqNum, names[i]);
00542         if (eqp == &eq[0])
00543         {
00544                     newRA = values[i];
00545             nset += newRA >= 0 && newRA <= 24.0;
00546         } else if (eqp == &eq[1])
00547         {
00548             newDEC = values[i];
00549             nset += newDEC >= -90.0 && newDEC <= 90.0;
00550         }
00551         }
00552 
00553       if (nset == 2)
00554       {
00555        /*eqNum.s = IPS_BUSY;*/
00556        char RAStr[32], DecStr[32];
00557 
00558        fs_sexa(RAStr, newRA, 2, 3600);
00559        fs_sexa(DecStr, newDEC, 2, 3600);
00560       
00561        IDLog("We received J2000 RA %g - DEC %g\n", newRA, newDEC);
00562        IDLog("We received J2000 RA %s - DEC %s\n", RAStr, DecStr);
00563        
00564        /*apparentCoord( (double) J2000, JD, &newRA, &newDEC);
00565        
00566        fs_sexa(RAStr, newRA, 2, 3600);
00567        fs_sexa(DecStr, newDEC, 2, 3600);
00568        
00569        IDLog("Processed to JNow RA %f - DEC %f\n", newRA, newDEC);
00570        IDLog("Processed to JNow RA %s - DEC %s\n", RAStr, DecStr);*/
00571 
00572        if ( (err = setObjectRA(newRA)) < 0 || ( err = setObjectDEC(newDEC)) < 0)
00573        {
00574          handleError(&eqNum, err, "Setting RA/DEC");
00575          return;
00576        } 
00577        
00578            /*eqNum.s = IPS_BUSY;*/
00579        targetRA  = newRA;
00580        targetDEC = newDEC;
00581        
00582        if (MovementSw.s == IPS_BUSY)
00583        {
00584         for (int i=0; i < 4; i++)
00585         {
00586                 lastMove[i] = 0;
00587                 MovementS[i].s = ISS_OFF;
00588         }
00589         
00590         MovementSw.s = IPS_IDLE;
00591         IDSetSwitch(&MovementSw, NULL);
00592        }
00593        
00594        if (handleCoordSet())
00595        {
00596          eqNum.s = IPS_IDLE;
00597          IDSetNumber(&eqNum, NULL);
00598          
00599        }
00600     } // end nset
00601     else
00602     {
00603         eqNum.s = IPS_IDLE;
00604         IDSetNumber(&eqNum, "RA or Dec missing or invalid");
00605     }
00606 
00607         return;
00608      } /* end eqNum */
00609 
00610         if ( !strcmp (name, SDTime.name) )
00611     {
00612       if (checkPower(&SDTime))
00613        return;
00614 
00615 
00616       if (values[0] < 0.0 || values[0] > 24.0)
00617       {
00618         SDTime.s = IPS_IDLE;
00619         IDSetNumber(&SDTime , "Time invalid");
00620         return;
00621       }
00622 
00623       getSexComponents(values[0], &h, &m, &s);
00624       IDLog("Time is %02d:%02d:%02d\n", h, m, s);
00625       
00626       if ( ( err = setSDTime(h, m, s) < 0) )
00627       {
00628         handleError(&SDTime, err, "Setting siderial time"); 
00629             return;
00630       }
00631       
00632       SDTime.np[0].value = values[0];
00633       SDTime.s = IPS_OK;
00634 
00635       IDSetNumber(&SDTime , "Sidereal time updated to %02d:%02d:%02d", h, m, s);
00636 
00637       return;
00638         }
00639 
00640     if (!strcmp (name, geoNum.name))
00641     {
00642         // new geographic coords
00643         double newLong = 0, newLat = 0;
00644         int i, nset;
00645         char msg[128];
00646 
00647       if (checkPower(&geoNum))
00648        return;
00649 
00650 
00651         for (nset = i = 0; i < n; i++)
00652         {
00653         INumber *geop = IUFindNumber (&geoNum, names[i]);
00654         if (geop == &geo[0])
00655         {
00656             newLat = values[i];
00657             nset += newLat >= -90.0 && newLat <= 90.0;
00658         } else if (geop == &geo[1])
00659         {
00660             newLong = values[i];
00661             nset += newLong >= 0.0 && newLong < 360.0;
00662         }
00663         }
00664 
00665         if (nset == 2)
00666         {
00667         char l[32], L[32];
00668         geoNum.s = IPS_OK;
00669         fs_sexa (l, newLat, 3, 3600);
00670         fs_sexa (L, newLong, 4, 3600);
00671         
00672         if ( ( err = setSiteLongitude(360.0 - newLong) < 0) )
00673             {
00674            handleError(&geoNum, err, "Setting site coordinates");
00675            return;
00676              }
00677         
00678         setSiteLatitude(newLat);
00679         geoNum.np[0].value = newLat;
00680         geoNum.np[1].value = newLong;
00681         snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
00682         } else
00683         {
00684         geoNum.s = IPS_IDLE;
00685         strcpy(msg, "Lat or Long missing or invalid");
00686         }
00687         IDSetNumber (&geoNum, "%s", msg);
00688         return;
00689     }
00690 
00691     if ( !strcmp (name, TrackingFreq.name) )
00692     {
00693 
00694      if (checkPower(&TrackingFreq))
00695       return;
00696 
00697       IDLog("Trying to set track freq of: %f\n", values[0]);
00698 
00699       if ( ( err = setTrackFreq(values[0])) < 0) 
00700       {
00701              handleError(&TrackingFreq, err, "Setting tracking frequency");
00702          return;
00703      }
00704      
00705      TrackingFreq.s = IPS_OK;
00706      TrackingFreq.np[0].value = values[0];
00707      IDSetNumber(&TrackingFreq, "Tracking frequency set to %04.1f", values[0]);
00708      if (trackingMode != LX200_TRACK_MANUAL)
00709      {
00710           trackingMode = LX200_TRACK_MANUAL;
00711           TrackModeS[0].s = ISS_OFF;
00712           TrackModeS[1].s = ISS_OFF;
00713           TrackModeS[2].s = ISS_ON;
00714           TrackModeSw.s   = IPS_OK;
00715           selectTrackingMode(trackingMode);
00716           IDSetSwitch(&TrackModeSw, NULL);
00717      }
00718      
00719       return;
00720     }
00721     
00722     if (!strcmp(name, FocusTimerNP.name))
00723     {
00724       if (checkPower(&FocusTimerNP))
00725        return;
00726        
00727       // Don't update if busy
00728       if (FocusTimerNP.s == IPS_BUSY)
00729        return;
00730        
00731       IUUpdateNumbers(&FocusTimerNP, values, names, n);
00732       
00733       FocusTimerNP.s = IPS_OK;
00734       
00735       IDSetNumber(&FocusTimerNP, NULL);
00736       IDLog("Setting focus timer to %g\n", FocusTimerN[0].value);
00737       
00738       return;
00739 
00740     }
00741 
00742         // Focus speed
00743     if (!strcmp (name, FocusSpeedNP.name))
00744     {
00745       if (checkPower(&FocusSpeedNP))
00746        return;
00747 
00748       if (IUUpdateNumbers(&FocusSpeedNP, values, names, n) < 0)
00749         return;
00750 
00751       /* disable timer and motion */
00752       if (FocusSpeedN[0].value == 0)
00753       {
00754         IUResetSwitches(&FocusMotionSw);
00755         FocusMotionSw.s = IPS_IDLE;
00756         FocusTimerNP.s  = IPS_IDLE;
00757         IDSetSwitch(&FocusMotionSw, NULL);
00758         IDSetNumber(&FocusTimerNP, NULL);
00759       }
00760         
00761       setFocuserSpeedMode( ( (int) FocusSpeedN[0].value));
00762       FocusSpeedNP.s = IPS_OK;
00763       IDSetNumber(&FocusSpeedNP, NULL);
00764       return;
00765     }
00766 
00767 }
00768 
00769 void LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
00770 {
00771     int index;
00772     int dd, mm, err;
00773     char combinedDir[64];
00774     ISwitch *swp;
00775 
00776     // suppress warning
00777     names = names;
00778 
00779     //IDLog("in new Switch with Device= %s and Property= %s and #%d items\n", dev, name,n);
00780     //IDLog("SolarSw name is %s\n", SolarSw.name);
00781 
00782     //IDLog("The device name is %s\n", dev);
00783     // ignore if not ours //
00784     if (strcmp (thisDevice, dev))
00785         return;
00786 
00787     // FIRST Switch ALWAYS for power
00788     if (!strcmp (name, PowerSP.name))
00789     {
00790      IUResetSwitches(&PowerSP);
00791      IUUpdateSwitches(&PowerSP, states, names, n);
00792      powerTelescope();
00793      return;
00794     }
00795 
00796     // Coord set
00797     if (!strcmp(name, OnCoordSetSw.name))
00798     {
00799       if (checkPower(&OnCoordSetSw))
00800        return;
00801 
00802       IUResetSwitches(&OnCoordSetSw);
00803       IUUpdateSwitches(&OnCoordSetSw, states, names, n);
00804       currentSet = getOnSwitch(&OnCoordSetSw);
00805       OnCoordSetSw.s = IPS_OK;
00806       IDSetSwitch(&OnCoordSetSw, NULL);
00807     }
00808     
00809     // Parking
00810     if (!strcmp(name, ParkSP.name))
00811     {
00812       if (checkPower(&ParkSP))
00813         return;
00814            
00815        ParkSP.s = IPS_IDLE;
00816        
00817 
00818        if ( (err = getSDTime(&STime[0].value)) < 0)
00819        {
00820         handleError(&ParkSP, err, "Get siderial time");
00821         return;
00822        }
00823        
00824        if (AlignmentS[0].s == ISS_ON)
00825        {
00826          targetRA  = STime[0].value;
00827          targetDEC = 0;
00828          setObjectRA(targetRA);
00829          setObjectDEC(targetDEC);
00830        }
00831        
00832        else if (AlignmentS[1].s == ISS_ON)
00833        {
00834          targetRA  = calculateRA(STime[0].value);
00835          targetDEC = calculateDec(geo[0].value, STime[0].value);
00836          setObjectRA(targetRA);
00837          setObjectDEC(targetDEC);
00838          IDLog("Parking the scope in AltAz (0,0) which corresponds to (RA,DEC) of (%g,%g)\n", targetRA, targetDEC);
00839          IDLog("Current Sidereal time is: %g\n", STime[0].value);
00840          IDSetNumber(&SDTime, NULL);
00841        }
00842        else
00843        {
00844          IDSetSwitch(&ParkSP, "You can only park the telescope in Polar or AltAz modes.");
00845          return;
00846        }
00847        
00848        IDSetNumber(&SDTime, NULL);
00849        
00850        currentSet = LX200_PARK;
00851        handleCoordSet();
00852     }
00853       
00854     // Abort Slew
00855     if (!strcmp (name, abortSlewSw.name))
00856     {
00857       if (checkPower(&abortSlewSw))
00858       {
00859         abortSlewSw.s = IPS_IDLE;
00860         IDSetSwitch(&abortSlewSw, NULL);
00861         return;
00862       }
00863       
00864       IUResetSwitches(&abortSlewSw);
00865       abortSlew();
00866 
00867         if (eqNum.s == IPS_BUSY)
00868         {
00869         abortSlewSw.s = IPS_OK;
00870         eqNum.s       = IPS_IDLE;
00871         IDSetSwitch(&abortSlewSw, "Slew aborted.");
00872         IDSetNumber(&eqNum, NULL);
00873             }
00874         else if (MovementSw.s == IPS_BUSY)
00875         {
00876             
00877         for (int i=0; i < 4; i++)
00878           lastMove[i] = 0;
00879         
00880         MovementSw.s  = IPS_IDLE; 
00881         abortSlewSw.s = IPS_OK;     
00882         eqNum.s       = IPS_IDLE;
00883         IUResetSwitches(&MovementSw);
00884         IUResetSwitches(&abortSlewSw);
00885         IDSetSwitch(&abortSlewSw, "Slew aborted.");
00886         IDSetSwitch(&MovementSw, NULL);
00887         IDSetNumber(&eqNum, NULL);
00888         }
00889         else
00890         {
00891             IUResetSwitches(&MovementSw);
00892             abortSlewSw.s = IPS_OK;
00893             IDSetSwitch(&abortSlewSw, NULL);
00894         }
00895 
00896         return;
00897     }
00898 
00899     // Alignment
00900     if (!strcmp (name, AlignmentSw.name))
00901     {
00902       if (checkPower(&AlignmentSw))
00903        return;
00904 
00905       IUResetSwitches(&AlignmentSw);
00906       IUUpdateSwitches(&AlignmentSw, states, names, n);
00907       index = getOnSwitch(&AlignmentSw);
00908 
00909       if ( ( err = setAlignmentMode(index) < 0) )
00910       {
00911          handleError(&AlignmentSw, err, "Setting alignment");
00912              return;
00913       }
00914       
00915       AlignmentSw.s = IPS_OK;
00916           IDSetSwitch (&AlignmentSw, NULL);
00917       return;
00918 
00919     }
00920 
00921         // Sites
00922     if (!strcmp (name, SitesSw.name))
00923     {
00924       if (checkPower(&SitesSw))
00925        return;
00926 
00927       IUResetSwitches(&SitesSw);
00928       IUUpdateSwitches(&SitesSw, states, names, n);
00929       currentSiteNum = getOnSwitch(&SitesSw) + 1;
00930       
00931       if ( ( err = selectSite(currentSiteNum) < 0) )
00932       {
00933           handleError(&SitesSw, err, "Selecting sites");
00934           return;
00935       }
00936 
00937       if ( ( err = getSiteLatitude(&dd, &mm) < 0))
00938       {
00939           handleError(&SitesSw, err, "Selecting sites");
00940           return;
00941       }
00942 
00943       if (dd > 0) geoNum.np[0].value = dd + mm / 60.0;
00944       else geoNum.np[0].value = dd - mm / 60.0;
00945       
00946       if ( ( err = getSiteLongitude(&dd, &mm) < 0))
00947       {
00948             handleError(&SitesSw, err, "Selecting sites");
00949         return;
00950       }
00951       
00952       if (dd > 0) geoNum.np[1].value = 360.0 - (dd + mm / 60.0);
00953       else geoNum.np[1].value = (dd - mm / 60.0) * -1.0;
00954       
00955       getSiteName( SiteName.tp[0].text, currentSiteNum);
00956 
00957       IDLog("Selecting site %d\n", currentSiteNum);
00958       
00959       geoNum.s = SiteName.s = SitesSw.s = IPS_OK;
00960 
00961       IDSetNumber (&geoNum, NULL);
00962       IDSetText   (&SiteName, NULL);
00963           IDSetSwitch (&SitesSw, NULL);
00964       return;
00965     }
00966 
00967     // Focus Motion
00968     if (!strcmp (name, FocusMotionSw.name))
00969     {
00970       if (checkPower(&FocusMotionSw))
00971        return;
00972 
00973       IUResetSwitches(&FocusMotionSw);
00974       
00975       // If speed is "halt"
00976       if (FocusSpeedN[0].value == 0)
00977       {
00978         FocusMotionSw.s = IPS_IDLE;
00979         IDSetSwitch(&FocusMotionSw, NULL);
00980         return;
00981       }
00982       
00983       IUUpdateSwitches(&FocusMotionSw, states, names, n);
00984       index = getOnSwitch(&FocusMotionSw);
00985       
00986       
00987       if ( ( err = setFocuserMotion(index) < 0) )
00988       {
00989          handleError(&FocusMotionSw, err, "Setting focuser speed");
00990              return;
00991       }
00992       
00993       
00994       FocusMotionSw.s = IPS_BUSY;
00995       
00996       // with a timer 
00997       if (FocusTimerN[0].value > 0)  
00998          FocusTimerNP.s  = IPS_BUSY;
00999       
01000       IDSetSwitch(&FocusMotionSw, NULL);
01001       return;
01002     }
01003 
01004     // Slew mode
01005     if (!strcmp (name, SlewModeSw.name))
01006     {
01007       if (checkPower(&SlewModeSw))
01008        return;
01009 
01010       IUResetSwitches(&SlewModeSw);
01011       IUUpdateSwitches(&SlewModeSw, states, names, n);
01012       index = getOnSwitch(&SlewModeSw);
01013        
01014       if ( ( err = setSlewMode(index) < 0) )
01015       {
01016               handleError(&SlewModeSw, err, "Setting slew mode");
01017               return;
01018       }
01019       
01020           SlewModeSw.s = IPS_OK;
01021       IDSetSwitch(&SlewModeSw, NULL);
01022       return;
01023     }
01024 
01025     // Movement
01026     if (!strcmp (name, MovementSw.name))
01027     {
01028       if (checkPower(&MovementSw))
01029        return;
01030 
01031      index = -1;
01032      IUUpdateSwitches(&MovementSw, states, names, n);
01033      swp = IUFindSwitch(&MovementSw, names[0]);
01034      
01035      if (!swp)
01036      {
01037         abortSlew();
01038         IUResetSwitches(&MovementSw);
01039         MovementSw.s = IPS_IDLE;
01040         IDSetSwitch(&MovementSw, NULL);
01041      }
01042      
01043      if (swp == &MovementS[0]) index = 0;
01044      else if (swp == &MovementS[1]) index = 1;
01045      else if (swp == &MovementS[2]) index = 2;
01046      else index = 3;
01047      
01048      lastMove[index] = lastMove[index] == 0 ? 1 : 0;
01049      if (lastMove[index] == 0)
01050        MovementS[index].s = ISS_OFF;
01051          
01052        // North/South movement is illegal
01053        if (lastMove[LX200_NORTH] && lastMove[LX200_SOUTH])  
01054        {
01055          abortSlew();
01056           for (int i=0; i < 4; i++)
01057             lastMove[i] = 0;
01058             
01059           IUResetSwitches(&MovementSw);
01060           MovementSw.s       = IPS_IDLE;
01061           IDSetSwitch(&MovementSw, "Slew aborted.");
01062           return;
01063        }
01064        
01065        // East/West movement is illegal
01066        if (lastMove[LX200_EAST] && lastMove[LX200_WEST])    
01067        {
01068           abortSlew();
01069           for (int i=0; i < 4; i++)
01070                 lastMove[i] = 0;
01071            
01072           IUResetSwitches(&MovementSw);
01073               MovementSw.s       = IPS_IDLE;
01074           IDSetSwitch(&MovementSw, "Slew aborted.");
01075           return;
01076        }
01077           
01078           IDLog("We have switch %d \n ", index);
01079       IDLog("NORTH: %d -- WEST: %d -- EAST: %d -- SOUTH %d\n", lastMove[0], lastMove[1], lastMove[2], lastMove[3]);
01080 
01081       if (lastMove[index] == 1)
01082       {
01083             IDLog("issuing a move command\n");
01084             if ( ( err = MoveTo(index) < 0) )
01085         {
01086                  handleError(&MovementSw, err, "Setting motion direction");
01087             return;
01088         }
01089       }
01090       else
01091          HaltMovement(index);
01092 
01093           if (!lastMove[0] && !lastMove[1] && !lastMove[2] && !lastMove[3])
01094          MovementSw.s = IPS_IDLE;
01095       
01096       if (lastMove[index] == 0)
01097          IDSetSwitch(&MovementSw, "Moving toward %s aborted.", Direction[index]);
01098       else
01099       {
01100          MovementSw.s = IPS_BUSY;
01101          if (lastMove[LX200_NORTH] && lastMove[LX200_WEST])
01102            strcpy(combinedDir, "North West");
01103          else if (lastMove[LX200_NORTH] && lastMove[LX200_EAST])
01104            strcpy(combinedDir, "North East");
01105          else if (lastMove[LX200_SOUTH] && lastMove[LX200_WEST])
01106            strcpy(combinedDir, "South West");
01107          else if (lastMove[LX200_SOUTH] && lastMove[LX200_EAST])
01108            strcpy(combinedDir, "South East");
01109          else 
01110            strcpy(combinedDir, Direction[index]);
01111          
01112          IDSetSwitch(&MovementSw, "Moving %s...", combinedDir);
01113       }
01114       return;
01115     }
01116 
01117     // Tracking mode
01118     if (!strcmp (name, TrackModeSw.name))
01119     {
01120       if (checkPower(&TrackModeSw))
01121        return;
01122 
01123       IUResetSwitches(&TrackModeSw);
01124       IUUpdateSwitches(&TrackModeSw, states, names, n);
01125       trackingMode = getOnSwitch(&TrackModeSw);
01126       
01127       if ( ( err = selectTrackingMode(trackingMode) < 0) )
01128       {
01129              handleError(&TrackModeSw, err, "Setting tracking mode.");
01130          return;
01131       }
01132       
01133           getTrackFreq(&TrackFreq[0].value);
01134       TrackModeSw.s = IPS_OK;
01135       IDSetNumber(&TrackingFreq, NULL);
01136       IDSetSwitch(&TrackModeSw, NULL);
01137       return;
01138     }
01139 
01140 }
01141 
01142 void LX200Generic::handleError(ISwitchVectorProperty *svp, int err, const char *msg)
01143 {
01144   
01145   svp->s = IPS_ALERT;
01146   
01147   /* First check to see if the telescope is connected */
01148     if (testTelescope())
01149     {
01150       /* The telescope is off locally */
01151       PowerS[0].s = ISS_OFF;
01152       PowerS[1].s = ISS_ON;
01153       PowerSP.s = IPS_BUSY;
01154       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
01155       
01156       IDSetSwitch(svp, NULL);
01157       IEAddTimer(10000, retryConnection, NULL);
01158       return;
01159     }
01160     
01161    /* If the error is a time out, then the device doesn't support this property or busy*/
01162       if (err == -2)
01163       {
01164        svp->s = IPS_ALERT;
01165        IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
01166       }
01167       else
01168     /* Changing property failed, user should retry. */
01169        IDSetSwitch( svp , "%s failed.", msg);
01170        
01171        fault = true;
01172 }
01173 
01174 void LX200Generic::handleError(INumberVectorProperty *nvp, int err, const char *msg)
01175 {
01176   
01177   nvp->s = IPS_ALERT;
01178   
01179   /* First check to see if the telescope is connected */
01180     if (testTelescope())
01181     {
01182       /* The telescope is off locally */
01183       PowerS[0].s = ISS_OFF;
01184       PowerS[1].s = ISS_ON;
01185       PowerSP.s = IPS_BUSY;
01186       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
01187       
01188       IDSetNumber(nvp, NULL);
01189       IEAddTimer(10000, retryConnection, NULL);
01190       return;
01191     }
01192     
01193    /* If the error is a time out, then the device doesn't support this property */
01194       if (err == -2)
01195       {
01196        nvp->s = IPS_ALERT;
01197        IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
01198       }
01199       else
01200     /* Changing property failed, user should retry. */
01201        IDSetNumber( nvp , "%s failed.", msg);
01202        
01203        fault = true;
01204 }
01205 
01206 void LX200Generic::handleError(ITextVectorProperty *tvp, int err, const char *msg)
01207 {
01208   
01209   tvp->s = IPS_ALERT;
01210   
01211   /* First check to see if the telescope is connected */
01212     if (testTelescope())
01213     {
01214       /* The telescope is off locally */
01215       PowerS[0].s = ISS_OFF;
01216       PowerS[1].s = ISS_ON;
01217       PowerSP.s = IPS_BUSY;
01218       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
01219       
01220       IDSetText(tvp, NULL);
01221       IEAddTimer(10000, retryConnection, NULL);
01222       return;
01223     }
01224     
01225    /* If the error is a time out, then the device doesn't support this property */
01226       if (err == -2)
01227       {
01228        tvp->s = IPS_ALERT;
01229        IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
01230       }
01231        
01232       else
01233     /* Changing property failed, user should retry. */
01234        IDSetText( tvp , "%s failed.", msg);
01235        
01236        fault = true;
01237 }
01238 
01239  void LX200Generic::correctFault()
01240  {
01241  
01242    fault = false;
01243    IDMessage(thisDevice, "Telescope is online.");
01244    
01245  }
01246 
01247 bool LX200Generic::isTelescopeOn(void)
01248 {
01249   if (simulation) return true;
01250   
01251   return (PowerSP.sp[0].s == ISS_ON);
01252 }
01253 
01254 static void retryConnection(void * p)
01255 {
01256   p=p;
01257   
01258   if (testTelescope())
01259   {
01260     PowerSP.s = IPS_IDLE;
01261     IDSetSwitch(&PowerSP, "The connection to the telescope is lost.");
01262     return;
01263   }
01264   
01265   PowerS[0].s = ISS_ON;
01266   PowerS[1].s = ISS_OFF;
01267   PowerSP.s = IPS_OK;
01268    
01269   IDSetSwitch(&PowerSP, "The connection to the telescope has been resumed.");
01270 
01271 }
01272 
01273 void LX200Generic::ISPoll()
01274 {
01275         double dx, dy;
01276     /*static int okCounter = 3;*/
01277     int err=0;
01278     
01279     if (!isTelescopeOn())
01280      return;
01281 
01282     switch (eqNum.s)
01283     {
01284     case IPS_IDLE:
01285     getLX200RA(&currentRA);
01286     getLX200DEC(&currentDEC);
01287     
01288         if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
01289     {
01290             eqNum.np[0].value = lastRA = currentRA;
01291         eqNum.np[1].value = lastDEC = currentDEC;
01292         IDSetNumber (&eqNum, NULL);
01293     }
01294         break;
01295 
01296         case IPS_BUSY:
01297         getLX200RA(&currentRA);
01298         getLX200DEC(&currentDEC);
01299         dx = targetRA - currentRA;
01300         dy = targetDEC - currentDEC;
01301 
01302         IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
01303         IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
01304 
01305         eqNum.np[0].value = currentRA;
01306         eqNum.np[1].value = currentDEC;
01307 
01308         // Wait until acknowledged or within threshold
01309         if (fabs(dx) <= RA_THRESHOLD && fabs(dy) <= DEC_THRESHOLD)
01310         {
01311           /* Don't set current to target. This might leave residual cumulative error 
01312         currentRA = targetRA;
01313         currentDEC = targetDEC;
01314           */
01315         
01316            eqNum.np[0].value = lastRA  = currentRA;
01317            eqNum.np[1].value = lastDEC = currentDEC;
01318            IUResetSwitches(&OnCoordSetSw);
01319            OnCoordSetSw.s = IPS_OK;
01320            eqNum.s = IPS_OK;
01321            IDSetNumber (&eqNum, NULL);
01322 
01323         switch (currentSet)
01324         {
01325           case LX200_SLEW:
01326             OnCoordSetSw.sp[0].s = ISS_ON;
01327             IDSetSwitch (&OnCoordSetSw, "Slew is complete.");
01328             break;
01329           
01330           case LX200_TRACK:
01331             OnCoordSetSw.sp[1].s = ISS_ON;
01332             IDSetSwitch (&OnCoordSetSw, "Slew is complete. Tracking...");
01333             break;
01334           
01335           case LX200_SYNC:
01336             break;
01337           
01338           case LX200_PARK:
01339                 if (setSlewMode(LX200_SLEW_GUIDE) < 0)
01340             { 
01341               handleError(&eqNum, err, "Setting slew mode");
01342               return;
01343             }
01344             
01345             IUResetSwitches(&SlewModeSw);
01346             SlewModeS[LX200_SLEW_GUIDE].s = ISS_ON;
01347             IDSetSwitch(&SlewModeSw, NULL);
01348             
01349             MoveTo(LX200_EAST);
01350             IUResetSwitches(&MovementSw);
01351             MovementS[LX200_EAST].s = ISS_ON;
01352             MovementSw.s = IPS_BUSY;
01353             for (int i=0; i < 4; i++)
01354               lastMove[i] = 0;
01355             lastMove[LX200_EAST] = 1;
01356             IDSetSwitch(&MovementSw, NULL);
01357             
01358             ParkSP.s = IPS_OK;
01359             IDSetSwitch (&ParkSP, "Park is complete. Turn off the telescope now.");
01360             break;
01361         }
01362 
01363         } else
01364         {
01365         eqNum.np[0].value = currentRA;
01366         eqNum.np[1].value = currentDEC;
01367         IDSetNumber (&eqNum, NULL);
01368         }
01369         break;
01370 
01371     case IPS_OK:
01372       
01373       /*if (--okCounter >= 0)
01374         break;
01375       
01376     // Activate again in 3 seconds
01377       okCounter = 3;*/
01378       
01379     if ( (err = getLX200RA(&currentRA)) < 0 || (err = getLX200DEC(&currentDEC)) < 0)
01380     {
01381       handleError(&eqNum, err, "Getting RA/DEC");
01382       return;
01383     }
01384     
01385     if (fault)
01386       correctFault();
01387     
01388     if ( (currentRA != lastRA) || (currentDEC != lastDEC))
01389     {
01390         eqNum.np[0].value = lastRA  = currentRA;
01391         eqNum.np[1].value = lastDEC = currentDEC;
01392         IDSetNumber (&eqNum, NULL);
01393     }
01394         break;
01395 
01396 
01397     case IPS_ALERT:
01398         break;
01399     }
01400 
01401     switch (MovementSw.s)
01402     {
01403       case IPS_IDLE:
01404        break;
01405      case IPS_BUSY:
01406        getLX200RA(&currentRA);
01407        getLX200DEC(&currentDEC);
01408        /*apparentCoord( JD, (double) J2000, &currentRA, &currentDEC);*/
01409        eqNum.np[0].value = currentRA;
01410        eqNum.np[1].value = currentDEC;
01411 
01412        IDSetNumber (&eqNum, NULL);
01413          break;
01414      case IPS_OK:
01415        break;
01416      case IPS_ALERT:
01417        break;
01418      }
01419      
01420      switch (FocusTimerNP.s)
01421      {
01422        case IPS_IDLE:
01423          break;
01424          
01425        case IPS_BUSY:
01426         FocusTimerN[0].value--;
01427         
01428         if (FocusTimerN[0].value == 0)
01429         {
01430           
01431           if ( ( err = setFocuserSpeedMode(0) < 0) )
01432               {
01433             handleError(&FocusSpeedNP, err, "setting focuser speed mode");
01434                 IDLog("Error setting focuser speed mode\n");
01435                 return;
01436           } 
01437          
01438           
01439           FocusMotionSw.s = IPS_IDLE;
01440           FocusTimerNP.s  = IPS_OK;
01441           FocusSpeedNP.s  = IPS_OK;
01442           
01443               IUResetSwitches(&FocusMotionSw);
01444           FocusSpeedN[0].value = 0;
01445           
01446           IDSetNumber(&FocusSpeedNP, NULL);
01447           IDSetSwitch(&FocusMotionSw, NULL);
01448         }
01449         
01450         IDSetNumber(&FocusTimerNP, NULL);
01451         break;
01452         
01453        case IPS_OK:
01454         break;
01455         
01456        case IPS_ALERT:
01457         break;
01458      }
01459     
01460 
01461 }
01462 
01463 void LX200Generic::getBasicData()
01464 {
01465 
01466   int err;
01467   struct tm *timep;
01468   time_t ut;
01469   time (&ut);
01470   timep = gmtime (&ut);
01471   strftime (Time.tp[0].text, sizeof(Time.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep);
01472 
01473   IDLog("PC UTC time is %s\n", Time.tp[0].text);
01474 
01475   getAlignment();
01476   
01477   checkLX200Format();
01478   
01479   if ( (err = getTimeFormat(&timeFormat)) < 0)
01480      IDMessage(thisDevice, "Failed to retrieve time format from device.");
01481   else
01482   {
01483     timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM;
01484     // We always do 24 hours
01485     if (timeFormat != LX200_24)
01486       toggleTimeFormat();
01487   }
01488 
01489   getLX200RA(&targetRA);
01490   getLX200DEC(&targetDEC);
01491 
01492   eqNum.np[0].value = targetRA;
01493   eqNum.np[1].value = targetDEC;
01494   
01495   IDSetNumber (&eqNum, NULL);  
01496   
01497   SiteNameT[0].text = new char[64];
01498   
01499   if ( (err = getSiteName(SiteNameT[0].text, currentSiteNum)) < 0)
01500     IDMessage(thisDevice, "Failed to get site name from device");
01501   else
01502     IDSetText   (&SiteName, NULL);
01503   
01504   if ( (err = getTrackFreq(&TrackFreq[0].value)) < 0)
01505      IDMessage(thisDevice, "Failed to get tracking frequency from device.");
01506   else
01507      IDSetNumber (&TrackingFreq, NULL);
01508      
01509      
01510   updateLocation();
01511   updateTime();
01512   
01513 }
01514 
01515 int LX200Generic::handleCoordSet()
01516 {
01517 
01518   int  err;
01519   char syncString[256];
01520   char RAStr[32], DecStr[32];
01521   double dx, dy;
01522   
01523   IDLog("In Handle Coord Set()\n");
01524 
01525   switch (currentSet)
01526   {
01527 
01528     // Slew
01529     case LX200_SLEW:
01530           lastSet = LX200_SLEW;
01531       if (eqNum.s == IPS_BUSY)
01532       {
01533          IDLog("Aboring Slew\n");
01534          abortSlew();
01535 
01536          // sleep for 100 mseconds
01537          usleep(100000);
01538       }
01539 
01540       if ((err = Slew()))
01541       {
01542         slewError(err);
01543         return (-1);
01544       }
01545 
01546       eqNum.s = IPS_BUSY;
01547       fs_sexa(RAStr, targetRA, 2, 3600);
01548       fs_sexa(DecStr, targetDEC, 2, 3600);
01549       IDSetNumber(&eqNum, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
01550       IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
01551       break;
01552 
01553      // Track
01554      case LX200_TRACK:
01555           IDLog("We're in LX200_TRACK\n");
01556           if (eqNum.s == IPS_BUSY)
01557       {
01558          IDLog("Aboring Slew\n");
01559          abortSlew();
01560 
01561          // sleep for 200 mseconds
01562          usleep(200000);
01563       }
01564 
01565       dx = fabs ( targetRA - currentRA );
01566       dy = fabs (targetDEC - currentDEC);
01567 
01568       
01569       if (dx >= TRACKING_THRESHOLD || dy >= TRACKING_THRESHOLD) 
01570       {
01571             IDLog("Exceeded Tracking threshold, will attempt to slew to the new target.\n");
01572         IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
01573             IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
01574 
01575             if ((err = Slew()))
01576         {
01577                 slewError(err);
01578                 return (-1);
01579         }
01580 
01581         fs_sexa(RAStr, targetRA, 2, 3600);
01582             fs_sexa(DecStr, targetDEC, 2, 3600);
01583         eqNum.s = IPS_BUSY;
01584         IDSetNumber(&eqNum, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
01585         IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
01586       }
01587       else
01588       {
01589         IDLog("Tracking called, but tracking threshold not reached yet.\n");
01590         eqNum.s = IPS_OK;
01591         eqNum.np[0].value = currentRA;
01592         eqNum.np[1].value = currentDEC;
01593 
01594         if (lastSet != LX200_TRACK)
01595           IDSetNumber(&eqNum, "Tracking...");
01596         else
01597           IDSetNumber(&eqNum, NULL);
01598       }
01599       lastSet = LX200_TRACK;
01600       break;
01601 
01602     // Sync
01603     case LX200_SYNC:
01604           lastSet = LX200_SYNC;
01605       eqNum.s = IPS_IDLE;
01606        
01607       if ( ( err = Sync(syncString) < 0) )
01608       {
01609             IDSetNumber( &eqNum , "Synchronization failed.");
01610         return (-1);
01611       }
01612 
01613       eqNum.s = IPS_OK;
01614       IDLog("Synchronization successful %s\n", syncString);
01615       IDSetNumber(&eqNum, "Synchronization successful.");
01616       break;
01617 
01618    // PARK
01619    // Set RA to LST and DEC to 0 degrees, slew, then change to 'guide' slew after slew is complete.
01620    case LX200_PARK:
01621           if (eqNum.s == IPS_BUSY)
01622       {
01623          abortSlew();
01624 
01625          // sleep for 200 mseconds
01626          usleep(200000);
01627       }
01628 
01629       if ((err = Slew()))
01630       {
01631             slewError(err);
01632             return (-1);
01633       }
01634         
01635       ParkSP.s = IPS_BUSY;
01636       eqNum.s = IPS_BUSY;
01637       IDSetNumber(&eqNum, NULL);
01638       IDSetSwitch(&ParkSP, "The telescope is slewing to park position. Turn off the telescope after park is complete.");
01639       
01640       break;
01641       
01642    }
01643    
01644    return (0);
01645 
01646 }
01647 
01648 int LX200Generic::getOnSwitch(ISwitchVectorProperty *sp)
01649 {
01650  for (int i=0; i < sp->nsp ; i++)
01651      if (sp->sp[i].s == ISS_ON)
01652       return i;
01653 
01654  return -1;
01655 }
01656 
01657 
01658 int LX200Generic::checkPower(ISwitchVectorProperty *sp)
01659 {
01660   if (simulation) return 0;
01661   
01662   if (PowerSP.s != IPS_OK)
01663   {
01664     if (!strcmp(sp->label, ""))
01665         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name);
01666     else
01667         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label);
01668     
01669     sp->s = IPS_IDLE;
01670     IDSetSwitch(sp, NULL);
01671     return -1;
01672   }
01673 
01674   return 0;
01675 }
01676 
01677 int LX200Generic::checkPower(INumberVectorProperty *np)
01678 {
01679   if (simulation) return 0;
01680   
01681   if (PowerSP.s != IPS_OK)
01682   {
01683     
01684     if (!strcmp(np->label, ""))
01685         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name);
01686     else
01687         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label);
01688     
01689     np->s = IPS_IDLE;
01690     IDSetNumber(np, NULL);
01691     return -1;
01692   }
01693 
01694   return 0;
01695 
01696 }
01697 
01698 int LX200Generic::checkPower(ITextVectorProperty *tp)
01699 {
01700 
01701   if (simulation) return 0;
01702   
01703   if (PowerSP.s != IPS_OK)
01704   {
01705     if (!strcmp(tp->label, ""))
01706         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name);
01707     else
01708         IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label);
01709     
01710     tp->s = IPS_IDLE;
01711     IDSetText(tp, NULL);
01712     return -1;
01713   }
01714 
01715   return 0;
01716 
01717 }
01718 
01719 void LX200Generic::powerTelescope()
01720 {
01721      switch (PowerSP.sp[0].s)
01722      {
01723       case ISS_ON:  
01724     
01725         if (simulation)
01726     {
01727       PowerSP.s = IPS_OK;
01728       IDSetSwitch (&PowerSP, "Simulated telescope is online.");
01729       updateTime();
01730       return;
01731     }
01732     
01733          if (Connect(Port.tp[0].text))
01734      {
01735        PowerS[0].s = ISS_OFF;
01736        PowerS[1].s = ISS_ON;
01737        IDSetSwitch (&PowerSP, "Error connecting to port %s\n", Port.tp[0].text);
01738        return;
01739      }
01740      if (testTelescope())
01741      {   
01742        PowerS[0].s = ISS_OFF;
01743        PowerS[1].s = ISS_ON;
01744        IDSetSwitch (&PowerSP, "Error connecting to Telescope. Telescope is offline.");
01745        return;
01746      }
01747 
01748         IDLog("telescope test successfful\n");
01749     PowerSP.s = IPS_OK;
01750     IDSetSwitch (&PowerSP, "Telescope is online. Retrieving basic data...");
01751     getBasicData();
01752     break;
01753 
01754      case ISS_OFF:
01755          PowerS[0].s = ISS_OFF;
01756      PowerS[1].s = ISS_ON;
01757          PowerSP.s = IPS_IDLE;
01758          IDSetSwitch (&PowerSP, "Telescope is offline.");
01759      IDLog("Telescope is offline.");
01760      Disconnect();
01761      break;
01762 
01763     }
01764 
01765 }
01766 
01767 void LX200Generic::slewError(int slewCode)
01768 {
01769     OnCoordSetSw.s = IPS_IDLE;
01770     ParkSP.s = IPS_IDLE;
01771     IDSetSwitch(&ParkSP, NULL);
01772 
01773     if (slewCode == 1)
01774     IDSetSwitch (&OnCoordSetSw, "Object below horizon.");
01775     else if (slewCode == 2)
01776     IDSetSwitch (&OnCoordSetSw, "Object below the minimum elevation limit.");
01777     else
01778         IDSetSwitch (&OnCoordSetSw, "Slew failed.");
01779     
01780 
01781 }
01782 
01783 void LX200Generic::getAlignment()
01784 {
01785 
01786    if (PowerSP.s != IPS_OK)
01787     return;
01788 
01789    signed char align = ACK();
01790    if (align < 0)
01791    {
01792      IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment.");
01793      return;
01794    }
01795 
01796    AlignmentS[0].s = ISS_OFF;
01797    AlignmentS[1].s = ISS_OFF;
01798    AlignmentS[2].s = ISS_OFF;
01799 
01800     switch (align)
01801     {
01802       case 'P': AlignmentS[0].s = ISS_ON;
01803             break;
01804       case 'A': AlignmentS[1].s = ISS_ON;
01805             break;
01806       case 'L': AlignmentS[2].s = ISS_ON;
01807                 break;
01808     }
01809 
01810     AlignmentSw.s = IPS_OK;
01811     IDSetSwitch (&AlignmentSw, NULL);
01812     IDLog("ACK success %c\n", align);
01813 }
01814 
01815 void LX200Generic::enableSimulation(bool enable)
01816 {
01817    simulation = enable;
01818    
01819    if (simulation)
01820      IDLog("Warning: Simulation is activated.\n");
01821    else
01822      IDLog("Simulation is disabled.\n");
01823 }
01824 
01825 void LX200Generic::updateTime()
01826 {
01827 
01828   char cdate[32];
01829   double ctime;
01830   int h, m, s;
01831   int day, month, year, result;
01832   int UTC_h, UTC_month, UTC_year, UTC_day, daysInFeb;
01833   bool leapYear;
01834   
01835   tzset();
01836   
01837   UTCOffset = timezoneOffset();
01838   IDLog("Daylight: %s - TimeZone: %g\n", daylight ? "Yes" : "No", UTCOffset);
01839   
01840     
01841   if (simulation)
01842   {
01843     sprintf(UTC[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
01844     IDLog("Telescope ISO date and time: %s\n", UTC[0].text);
01845     IDSetText(&Time, NULL);
01846     return;
01847   }
01848   
01849   getLocalTime24(&ctime);
01850   getSexComponents(ctime, &h, &m, &s);
01851   
01852   UTC_h = h;
01853   
01854   if ( (result = getSDTime(&STime[0].value)) < 0)
01855     IDMessage(thisDevice, "Failed to retrieve siderial time from device.");
01856   
01857   getCalenderDate(cdate);
01858   
01859   result = sscanf(cdate, "%d/%d/%d", &year, &month, &day);
01860   if (result != 3) return;
01861   
01862   if (year % 4 == 0)
01863   {
01864     if (year % 100 == 0)
01865     {
01866       if (year % 400 == 0)
01867        leapYear = true;
01868       else 
01869        leapYear = false;
01870     }
01871     else
01872        leapYear = true;
01873   }
01874   else
01875        leapYear = false;
01876   
01877   daysInFeb = leapYear ? 29 : 28;
01878   
01879   UTC_year  = year; 
01880   UTC_month = month;
01881   UTC_day   = day;
01882   
01883   IDLog("day: %d - month %d - year: %d\n", day, month, year);
01884   
01885   // we'll have to convert telescope time to UTC manually starting from hour up
01886   // seems like a stupid way to do it.. oh well
01887   UTC_h = (int) UTCOffset + h;
01888   if (UTC_h < 0)
01889   {
01890    UTC_h += 24;
01891    UTC_day--;
01892   }
01893   else if (UTC_h > 24)
01894   {
01895    UTC_h -= 24;
01896    UTC_day++;
01897   }
01898   
01899   switch (UTC_month)
01900   {
01901     case 1:
01902     case 8:
01903      if (UTC_day < 1)
01904      {
01905         UTC_day = 31;
01906         UTC_month--;
01907      }
01908      else if (UTC_day > 31)
01909      {
01910        UTC_day = 1;
01911        UTC_month++;
01912      }
01913      break;
01914      
01915    case 2:
01916    if (UTC_day < 1)
01917      {
01918         UTC_day = 31;
01919         UTC_month--;
01920      }
01921      else if (UTC_day > daysInFeb)
01922      {
01923        UTC_day = 1;
01924        UTC_month++;
01925      }
01926      break;
01927      
01928   case 3:
01929      if (UTC_day < 1)
01930      {
01931         UTC_day = daysInFeb;
01932         UTC_month--;
01933      }
01934      else if (UTC_day > 31)
01935      {
01936        UTC_day = 1;
01937        UTC_month++;
01938      }
01939      break;
01940    
01941    case 4:
01942    case 6:
01943    case 9:
01944    case 11:
01945     if (UTC_day < 1)
01946      {
01947         UTC_day = 31;
01948         UTC_month--;
01949      }
01950      else if (UTC_day > 30)
01951      {
01952        UTC_day = 1;
01953        UTC_month++;
01954      }
01955      break;
01956    
01957    case 5:
01958    case 7:
01959    case 10:
01960    case 12:
01961     if (UTC_day < 1)
01962      {
01963         UTC_day = 30;
01964         UTC_month--;
01965      }
01966      else if (UTC_day > 31)
01967      {
01968        UTC_day = 1;
01969        UTC_month++;
01970      }
01971      break;
01972    
01973   }   
01974        
01975   if (UTC_month < 1)
01976   {
01977    UTC_month = 12;
01978    UTC_year--;
01979   }
01980   else if (UTC_month > 12)
01981   {
01982     UTC_month = 1;
01983     UTC_year++;
01984   }
01985   
01986   /* Format it into ISO 8601 */
01987   sprintf(UTC[0].text, "%d-%02d-%02dT%02d:%02d:%02d", UTC_year, UTC_month, UTC_day, UTC_h, m, s);
01988   
01989   IDLog("Local telescope time: %02d:%02d:%02d\n", h, m , s);
01990   IDLog("Telescope SD Time is: %g\n", STime[0].value);
01991   IDLog("UTC date and time: %s\n", UTC[0].text);
01992   
01993 
01994   // Let's send everything to the client
01995   IDSetText(&Time, NULL);
01996   IDSetNumber(&SDTime, NULL);
01997 
01998 }
01999 
02000 void LX200Generic::updateLocation()
02001 {
02002 
02003  int dd = 0, mm = 0, err = 0;
02004  
02005  if ( (err = getSiteLatitude(&dd, &mm)) < 0)
02006     IDMessage(thisDevice, "Failed to get site latitude from device.");
02007   else
02008   {
02009     if (dd > 0)
02010         geoNum.np[0].value = dd + mm/60.0;
02011     else
02012         geoNum.np[0].value = dd - mm/60.0;
02013   
02014       IDLog("Autostar Latitude: %d:%d\n", dd, mm);
02015       IDLog("INDI Latitude: %g\n", geoNum.np[0].value);
02016   }
02017   
02018   if ( (err = getSiteLongitude(&dd, &mm)) < 0)
02019     IDMessage(thisDevice, "Failed to get site longitude from device.");
02020   else
02021   {
02022     if (dd > 0) geoNum.np[1].value = 360.0 - (dd + mm/60.0);
02023     else geoNum.np[1].value = (dd - mm/60.0) * -1.0;
02024     
02025     IDLog("Autostar Longitude: %d:%d\n", dd, mm);
02026     IDLog("INDI Longitude: %g\n", geoNum.np[1].value);
02027   }
02028   
02029   IDSetNumber (&geoNum, NULL);
02030 
02031 }
02032 
02033 

kstars

Skip menu "kstars"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • keduca
  • kstars
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal