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

kstars

apmount.cpp

Go to the documentation of this file.
00001 #if 0
00002     Astro-Physics driver
00003     Copyright (C) 2005 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 "apmount.h"
00034 
00035 /*
00036 ** Return the timezone offset in hours (as a double, so fractional
00037 ** hours are possible, for instance in Newfoundland). Also sets
00038 ** daylight on non-Linux systems to record whether DST is in effect.
00039 */
00040 
00041 
00042 #if !(TIMEZONE_IS_INT)
00043 static int daylight = 0;
00044 #endif
00045 
00046 static inline double timezoneOffset()
00047 {
00048 /* 
00049 ** In Linux, there's a timezone variable that holds the timezone offset;
00050 ** Otherwise, we need to make a little detour. The directions of the offset
00051 ** are different: CET is -3600 in Linux and +3600 elsewhere.
00052 */
00053 #if TIMEZONE_IS_INT
00054   return timezone / (60 * 60);
00055 #else
00056   time_t now;
00057   struct tm *tm;
00058   now = time(NULL);
00059   tm = localtime(&now);
00060   daylight = tm->tm_isdst;
00061   return -(tm->tm_gmtoff) / (60 * 60);
00062 #endif
00063 }
00064 
00065 APMount *telescope = NULL;
00066 int MaxReticleFlashRate = 3;
00067 extern char* me;
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 
00076 
00077 #define COMM_GROUP  "Communication"
00078 #define BASIC_GROUP "Main Control"
00079 #define MOVE_GROUP  "Movement Control"
00080 #define FOCUS_GROUP     "Focus Control"
00081 
00082 #define mydev       "Astro-Physics"
00083 #define currentRA   EqN[0].value
00084 #define currentDEC  EqN[1].value
00085 
00086 #define RA_THRESHOLD    0.01
00087 #define DEC_THRESHOLD   0.05
00088 #define LX200_SLEW  0
00089 #define LX200_TRACK 1
00090 #define LX200_SYNC  2
00091 #define LX200_PARK  3
00092 
00093 static void ISPoll(void *);
00094 static void retryConnection(void *);
00095 
00096 /*INDI controls */
00097 
00098 
00099 /* send client definitions of all properties */
00100 void ISInit()
00101 {
00102   static int isInit=0;
00103 
00104  if (isInit)
00105   return;
00106 
00107  isInit = 1;
00108   
00109   telescope = new APMount();
00110   IEAddTimer (POLLMS, ISPoll, NULL);
00111 }
00112 
00113 void ISGetProperties (const char *dev)
00114 {
00115  ISInit(); 
00116  telescope->ISGetProperties(dev);
00117 }
00118 
00119 void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
00120 {
00121  ISInit();
00122  telescope->ISNewSwitch(dev, name, states, names, n);
00123 }
00124 
00125 void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
00126 {
00127  ISInit();
00128  telescope->ISNewText(dev, name, texts, names, n);
00129 }
00130 
00131 void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
00132 {
00133  ISInit();
00134  telescope->ISNewNumber(dev, name, values, names, n);
00135 }
00136 
00137 void ISPoll (void */*p*/)
00138 {
00139  telescope->ISPoll(); 
00140  IEAddTimer (POLLMS, ISPoll, NULL);
00141 }
00142 
00143 void ISNewBLOB (const char */*dev*/, const char */*name*/, int */*sizes[]*/, char **/*blobs[]*/, char **/*formats[]*/, char **/*names[]*/, int /*n*/)
00144 {}
00145 
00146 /**************************************************
00147 *** AP Mount
00148 ***************************************************/
00149 
00150 APMount::APMount()
00151 {
00152    struct tm *utp;
00153    time_t t;
00154    time (&t);
00155    utp = gmtime (&t);
00156 
00157    initProperties();
00158 
00159    currentSiteNum = 1;
00160    trackingMode   = 2;
00161    lastSet        = -1;
00162    fault          = false;
00163    simulation     = false;
00164    targetRA       = 0;
00165    targetDEC      = 0;
00166    currentSet     = 0;
00167    UTCOffset      = 0;
00168    lastMove[0] = lastMove[1] = lastMove[2] = lastMove[3] = 0;
00169 
00170    localTM = new tm;
00171    
00172    utp->tm_mon  += 1;
00173    utp->tm_year += 1900;
00174    JD = UTtoJD(utp);
00175    
00176    IDLog("Julian Day is %g\n", JD);
00177    IDLog("Initilizing from Astro-Physics device...\n");
00178    IDLog("Driver Version: 2005-05-26\n");
00179  
00180    //enableSimulation(true);  
00181 }
00182 
00183 void APMount::initProperties()
00184 {
00185 
00186    fillSwitch(&AlignmentS[0], "Polar", "", ISS_ON);
00187    fillSwitch(&AlignmentS[1], "AltAz", "", ISS_OFF);
00188    fillSwitchVector(&AlignmentSP, AlignmentS, NARRAY(AlignmentS), mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00189 
00190   fillSwitch(&PowerS[0], "CONNECT", "Connect", ISS_OFF);
00191   fillSwitch(&PowerS[1], "DISCONNECT", "Disconnect", ISS_ON);
00192   fillSwitchVector(&PowerSP, PowerS, NARRAY(PowerS), mydev, "CONNECTION", "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
00193 
00194   fillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON);
00195   fillSwitch(&OnCoordSetS[1], "TRACK", "Track", ISS_OFF);
00196   fillSwitch(&OnCoordSetS[2], "SYNC", "Sync", ISS_OFF);
00197   fillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00198 
00199   fillSwitch(&TrackModeS[0], "Lunar", "", ISS_OFF);
00200   fillSwitch(&TrackModeS[1], "Solar", "", ISS_OFF);
00201   fillSwitch(&TrackModeS[2], "Sideral", "", ISS_ON);
00202   fillSwitch(&TrackModeS[3], "Zero", "", ISS_OFF);
00203   fillSwitchVector(&TrackModeSP, TrackModeS, NARRAY(TrackModeS), mydev, "Tracking Mode", "",  MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00204 
00205    fillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF);
00206    fillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00207 
00208     fillSwitch(&ParkS[0], "PARK", "Park", ISS_OFF);
00209     fillSwitch(&ParkS[1], "UNPARK", "Unpark", ISS_OFF);
00210     fillSwitchVector(&ParkSP, ParkS, NARRAY(ParkS), mydev, "PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00211 
00212     fillSwitch(&MovementS[0], "N", "North", ISS_OFF); 
00213     fillSwitch(&MovementS[1], "W", "West", ISS_OFF); 
00214     fillSwitch(&MovementS[2], "E", "East", ISS_OFF); 
00215     fillSwitch(&MovementS[3], "S", "South", ISS_OFF); 
00216     fillSwitchVector(&MovementSP, MovementS, NARRAY(MovementS), mydev, "MOVEMENT", "Move toward", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00217 
00218   fillSwitch(&FocusMotionS[0], "IN", "Focus in", ISS_OFF);
00219   fillSwitch(&FocusMotionS[1], "OUT", "Focus out", ISS_OFF);
00220   fillSwitchVector(&FocusMotionSP, FocusMotionS, NARRAY(FocusMotionS), mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
00221 
00222   fillText(&PortT[0], "PORT", "Port", "/dev/ttyS0");
00223   fillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE);
00224 
00225   fillText(&UTCT[0], "UTC", "", "YYYY-MM-DDTHH:MM:SS");
00226   fillTextVector(&TimeTP, UTCT, NARRAY(UTCT), mydev, "TIME", "UTC Time", COMM_GROUP, IP_RW, 0, IPS_IDLE);
00227 
00228   fillText(&ObjectT[0], "OBJECT_NAME", "Name", "--");
00229   fillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
00230 
00231    fillNumber(&EqN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
00232    fillNumber(&EqN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
00233    fillNumberVector(&EqNP, EqN, NARRAY(EqN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
00234 
00235    fillNumber(&GeoN[0], "LAT",  "Lat.  D:M:S +N", "%10.6m",  -90.,  90., 0., 0.);
00236    fillNumber(&GeoN[1], "LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0.);
00237    fillNumberVector(&GeoNP, GeoN, NARRAY(GeoN), mydev, "GEOGRAPHIC_COORD", "Geographic Location", COMM_GROUP, IP_RW, 0, IPS_IDLE);
00238 
00239    fillNumber(&FocusTimerN[0], "TIMEOUT", "Timeout (s)", "%10.6m", 0., 120., 1., 0.);
00240    fillNumberVector(&FocusTimerNP, FocusTimerN, NARRAY(FocusTimerN), mydev, "FOCUS_TIMEOUT", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE);
00241 
00242    fillNumber(&SDTimeN[0], "LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0.);
00243    fillNumberVector(&SDTimeNP, SDTimeN, NARRAY(SDTimeN), mydev, "SDTIME", "Sidereal Time", COMM_GROUP, IP_RW, 0, IPS_IDLE);
00244 
00245    fillNumber(&HorN[0], "ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0.);
00246    fillNumber(&HorN[1], "AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0.);
00247    fillNumberVector(&HorNP, HorN, NARRAY(HorN), mydev, "HORIZONTAL_COORD", "Horizontal Coords", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
00248 
00249    fillNumber(&FocusSpeedN[0], "SPEED", "Speed", "%0.f", 0., 3., 1., 0.);
00250    fillNumberVector(&FocusSpeedNP, FocusSpeedN, NARRAY(FocusSpeedN), mydev, "FOCUS_SPEED", "Speed", FOCUS_GROUP, IP_RW, 0, IPS_IDLE);
00251 
00252 
00253 }
00254 
00255 void APMount::ISGetProperties(const char *dev)
00256 {
00257 
00258  if (dev && strcmp (mydev, dev))
00259     return;
00260 
00261   // COMM_GROUP
00262   IDDefSwitch(&PowerSP, NULL);
00263   IDDefText(&PortTP, NULL);
00264   IDDefSwitch(&AlignmentSP, NULL);
00265   IDDefText(&TimeTP, NULL);
00266   IDDefNumber(&SDTimeNP, NULL);
00267   IDDefNumber(&GeoNP, NULL);
00268   
00269   // MAIN CONTROL
00270   IDDefText(&ObjectTP, NULL);
00271   IDDefNumber(&EqNP, NULL);
00272   //IDDefNumber(&HorNP, NULL);
00273   IDDefSwitch(&OnCoordSetSP, NULL);
00274   IDDefSwitch(&AbortSlewSP, NULL);
00275   IDDefSwitch(&ParkSP, NULL);
00276   
00277   // MOVEMENT CONTROL
00278   IDDefSwitch(&TrackModeSP, NULL);
00279   IDDefSwitch(&MovementSP, NULL);
00280   
00281   // FOCUS CONTROL
00282   IDDefNumber(&FocusSpeedNP, NULL);
00283   IDDefSwitch(&FocusMotionSP, NULL);
00284   IDDefNumber(&FocusTimerNP, NULL);
00285 
00286   /* Send the basic data to the new client if the previous client(s) are already connected. */      
00287    if (PowerSP.s == IPS_OK)
00288        getBasicData();
00289 
00290 }
00291 
00292 void APMount::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int /*n*/)
00293 {
00294     int err;
00295     struct tm *ltp = new tm;
00296     struct tm utm;
00297     time_t ltime;
00298     time (&ltime);
00299     localtime_r (&ltime, ltp);
00300     IText *tp;
00301 
00302     // ignore if not ours 
00303     if (strcmp (dev, mydev))
00304         return;
00305 
00306     // Port name
00307     if (!strcmp(name, PortTP.name) )
00308     {
00309       PortTP.s = IPS_OK;
00310       tp = IUFindText( &PortTP, names[0] );
00311       if (!tp)
00312        return;
00313 
00314        IUSaveText(tp, texts[0]);
00315        IDSetText (&PortTP, NULL);
00316       return;
00317     }
00318 
00319        // Time
00320        if (!strcmp (name, TimeTP.name))
00321        {
00322       if (checkPower(&TimeTP))
00323        return;
00324       
00325       if (extractISOTime(texts[0], &utm) < 0)
00326       {
00327         TimeTP.s = IPS_IDLE;
00328         IDSetText(&TimeTP , "Time invalid");
00329         return;
00330       }
00331         ltp->tm_mon  += 1;
00332         ltp->tm_year += 1900;
00333 
00334         tzset();
00335         
00336         UTCOffset = timezoneOffset();
00337         
00338         IDLog("local time is %02d:%02d:%02d\nUTCOffset: %g\n", ltp->tm_hour, ltp->tm_min, ltp->tm_sec, UTCOffset);
00339         
00340         getSDTime(&SDTimeN[0].value);
00341         IDSetNumber(&SDTimeNP, NULL);
00342         
00343         if ( ( err = setUTCOffset(UTCOffset) < 0) )
00344         {
00345             TimeTP.s = IPS_ALERT;
00346             IDSetText( &TimeTP , "Setting UTC Offset failed.");
00347         return;
00348         }
00349         
00350         if ( ( err = setLocalTime(ltp->tm_hour, ltp->tm_min, ltp->tm_sec) < 0) )
00351         {
00352               handleError(&TimeTP, err, "Setting local time");
00353               return;
00354         }
00355 
00356         tp = IUFindText(&TimeTP, names[0]);
00357         if (!tp)
00358              return;
00359                  IUSaveText(tp, texts[0]);
00360         TimeTP.s = IPS_OK;
00361 
00362         // update JD
00363                 JD = UTtoJD(&utm);
00364 
00365         IDLog("New JD is %f\n", (float) JD);
00366 
00367         if ((localTM->tm_mday == ltp->tm_mday ) && (localTM->tm_mon == ltp->tm_mon) &&
00368             (localTM->tm_year == ltp->tm_year))
00369         {
00370           IDSetText(&TimeTP , "Time updated to %s", texts[0]);
00371           return;
00372         }
00373 
00374             delete (localTM);
00375         localTM = ltp;
00376         
00377         if ( ( err = setCalenderDate(ltp->tm_mday, ltp->tm_mon, ltp->tm_year) < 0) )
00378         {
00379                 handleError(&TimeTP, err, "Setting local date.");
00380                 return;
00381         }
00382         
00383         IDSetText(&TimeTP , "Date changed, updating planetary data...");
00384     }
00385 
00386        if (!strcmp (name, ObjectTP.name))
00387        {
00388       if (checkPower(&ObjectTP))
00389        return;
00390 
00391           IUSaveText(&ObjectT[0], texts[0]);
00392           ObjectTP.s = IPS_OK;
00393           IDSetText(&ObjectTP, NULL);
00394           return;
00395        }
00396           
00397 }
00398 
00399 
00400 void APMount::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
00401 {
00402     int h =0, m =0, s=0, err;
00403     double newRA =0, newDEC =0;
00404     
00405     // ignore if not ours //
00406     if (strcmp (dev, mydev))
00407         return;
00408 
00409     if (!strcmp (name, EqNP.name))
00410     {
00411       int i=0, nset=0;
00412 
00413       if (checkPower(&EqNP))
00414        return;
00415 
00416         for (nset = i = 0; i < n; i++)
00417         {
00418         INumber *eqp = IUFindNumber (&EqNP, names[i]);
00419         if (eqp == &EqN[0])
00420         {
00421                     newRA = values[i];
00422             nset += newRA >= 0 && newRA <= 24.0;
00423         } else if (eqp == &EqN[1])
00424         {
00425             newDEC = values[i];
00426             nset += newDEC >= -90.0 && newDEC <= 90.0;
00427         }
00428         }
00429 
00430       if (nset == 2)
00431       {
00432        char RAStr[32], DecStr[32];
00433 
00434        fs_sexa(RAStr, newRA, 2, 3600);
00435        fs_sexa(DecStr, newDEC, 2, 3600);
00436       
00437        IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC);
00438        IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);
00439        
00440        if ( (err = setObjectRA(newRA)) < 0 || ( err = setObjectDEC(newDEC)) < 0)
00441        {
00442          handleError(&EqNP, err, "Setting RA/DEC");
00443          return;
00444        } 
00445        
00446        targetRA  = newRA;
00447        targetDEC = newDEC;
00448        
00449        if (MovementSP.s == IPS_BUSY)
00450        {
00451         for (int i=0; i < 4; i++)
00452         {
00453                 lastMove[i] = 0;
00454                 MovementS[i].s = ISS_OFF;
00455         }
00456         
00457         MovementSP.s = IPS_IDLE;
00458         IDSetSwitch(&MovementSP, NULL);
00459        }
00460        
00461        if (handleCoordSet())
00462        {
00463          EqNP.s = IPS_IDLE;
00464          IDSetNumber(&EqNP, NULL);
00465          
00466        }
00467     } // end nset
00468     else
00469     {
00470         EqNP.s = IPS_IDLE;
00471         IDSetNumber(&EqNP, "RA or Dec missing or invalid");
00472     }
00473 
00474         return;
00475      } /* end EqNP */
00476 
00477     // Sideral Time
00478         if ( !strcmp (name, SDTimeNP.name) )
00479     {
00480 
00481       if (checkPower(&SDTimeNP))
00482        return;
00483 
00484       if (values[0] < 0.0 || values[0] > 24.0)
00485       {
00486         SDTimeNP.s = IPS_IDLE;
00487         IDSetNumber(&SDTimeNP , "Time invalid");
00488         return;
00489       }
00490 
00491       getSexComponents(values[0], &h, &m, &s);
00492       IDLog("Time is %02d:%02d:%02d\n", h, m, s);
00493       
00494       if ( ( err = setSDTime(h, m, s) < 0) )
00495       {
00496         handleError(&SDTimeNP, err, "Setting siderial time"); 
00497             return;
00498       }
00499       
00500       SDTimeNP.np[0].value = values[0];
00501       SDTimeNP.s = IPS_OK;
00502 
00503       IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s);
00504 
00505       return;
00506         }
00507 
00508     // Geographical location
00509     if (!strcmp (name, GeoNP.name))
00510     {
00511         // new geographic coords
00512         double newLong = 0, newLat = 0;
00513         int i, nset;
00514         char msg[128];
00515 
00516       if (checkPower(&GeoNP))
00517        return;
00518 
00519         for (nset = i = 0; i < n; i++)
00520         {
00521         INumber *geop = IUFindNumber (&GeoNP, names[i]);
00522         if (geop == &GeoN[0])
00523         {
00524             newLat = values[i];
00525             nset += newLat >= -90.0 && newLat <= 90.0;
00526         } else if (geop == &GeoN[1])
00527         {
00528             newLong = values[i];
00529             nset += newLong >= 0.0 && newLong < 360.0;
00530         }
00531         }
00532 
00533         if (nset == 2)
00534         {
00535         char l[32], L[32];
00536         GeoNP.s = IPS_OK;
00537         fs_sexa (l, newLat, 3, 3600);
00538         fs_sexa (L, newLong, 4, 3600);
00539         
00540         if ( ( err = setSiteLongitude(360.0 - newLong) < 0) )
00541             {
00542            handleError(&GeoNP, err, "Setting site coordinates");
00543            return;
00544              }
00545         
00546         setSiteLatitude(newLat);
00547         GeoNP.np[0].value = newLat;
00548         GeoNP.np[1].value = newLong;
00549         snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
00550         } else
00551         {
00552         GeoNP.s = IPS_IDLE;
00553         strcpy(msg, "Lat or Long missing or invalid");
00554         }
00555         IDSetNumber (&GeoNP, "%s", msg);
00556         return;
00557     }
00558     
00559         // Focus TImer
00560     if (!strcmp(name, FocusTimerNP.name))
00561     {
00562       if (checkPower(&FocusTimerNP))
00563        return;
00564        
00565       // Don't update if busy
00566       if (FocusTimerNP.s == IPS_BUSY)
00567        return;
00568        
00569       IUUpdateNumbers(&FocusTimerNP, values, names, n);
00570       
00571       FocusTimerNP.s = IPS_OK;
00572       
00573       IDSetNumber(&FocusTimerNP, NULL);
00574       IDLog("Setting focus timer to %g\n", FocusTimerN[0].value);
00575       
00576       return;
00577 
00578     }
00579 
00580         // Focus speed
00581     if (!strcmp (name, FocusSpeedNP.name))
00582     {
00583       if (checkPower(&FocusSpeedNP))
00584        return;
00585 
00586       if (IUUpdateNumbers(&FocusSpeedNP, values, names, n) < 0)
00587         return;
00588 
00589       /* disable timer and motion */
00590       if (FocusSpeedN[0].value == 0)
00591       {
00592         FocusMotionSP.s = IPS_IDLE;
00593         FocusTimerNP.s  = IPS_IDLE;
00594         IDSetSwitch(&FocusMotionSP, NULL);
00595         IDSetNumber(&FocusTimerNP, NULL);
00596       }
00597         
00598       setFocuserSpeedMode( ( (int) FocusSpeedN[0].value));
00599       FocusSpeedNP.s = IPS_OK;
00600       IDSetNumber(&FocusSpeedNP, NULL);
00601       return;
00602     }
00603 
00604 }
00605 
00606 void APMount::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
00607 {
00608     int index;
00609     int err;
00610     char combinedDir[64];
00611     ISwitch *swp;
00612 
00613     // ignore if not ours //
00614     if (strcmp (mydev, dev))
00615         return;
00616 
00617     // Connection
00618     if (!strcmp (name, PowerSP.name))
00619     {
00620      IUResetSwitches(&PowerSP);
00621      IUUpdateSwitches(&PowerSP, states, names, n);
00622      powerTelescope();
00623      return;
00624     }
00625 
00626     // Coord set
00627     if (!strcmp(name, OnCoordSetSP.name))
00628     {
00629       if (checkPower(&OnCoordSetSP))
00630        return;
00631 
00632       IUResetSwitches(&OnCoordSetSP);
00633       IUUpdateSwitches(&OnCoordSetSP, states, names, n);
00634       currentSet = getOnSwitch(&OnCoordSetSP);
00635       OnCoordSetSP.s = IPS_OK;
00636       IDSetSwitch(&OnCoordSetSP, NULL);
00637     }
00638     
00639     // Parking
00640     if (!strcmp(name, ParkSP.name))
00641     {
00642       if (checkPower(&ParkSP))
00643         return;
00644            
00645        IUResetSwitches(&ParkSP);
00646        IUUpdateSwitches(&ParkSP, states, names, n);
00647        index = getOnSwitch(&ParkSP);
00648 
00649        // Park Command
00650        if (index == 0)
00651         APPark();
00652        else
00653        // Unpark
00654        {
00655         char **tmtexts = (char **) malloc(1);
00656         char **tmtp    = (char **) malloc(1);
00657         tmtexts[0]     = (char *) malloc (32);
00658         tmtp[0]        = (char *) malloc (32);
00659 
00660         strcpy(tmtexts[0], timestamp());
00661         strcpy(tmtp[0], "UTC");
00662 
00663         // Update date and time before unparking
00664         ISNewText(mydev, "TIME", tmtexts, tmtp, 1);
00665         APUnpark();
00666 
00667         free (tmtexts);
00668         free (tmtp);
00669        }
00670 
00671        ParkSP.s = IPS_OK;
00672        IDSetSwitch(&ParkSP, (index == 0) ? "Parking..." : "Unparking...");
00673        return;
00674     }
00675       
00676     // Abort Slew
00677     if (!strcmp (name, AbortSlewSP.name))
00678     {
00679       if (checkPower(&AbortSlewSP))
00680       {
00681         AbortSlewSP.s = IPS_IDLE;
00682         IDSetSwitch(&AbortSlewSP, NULL);
00683         return;
00684       }
00685       
00686       IUResetSwitches(&AbortSlewSP);
00687       abortSlew();
00688 
00689         if (EqNP.s == IPS_BUSY)
00690         {
00691         AbortSlewSP.s = IPS_OK;
00692         EqNP.s       = IPS_IDLE;
00693         IDSetSwitch(&AbortSlewSP, "Slew aborted.");
00694         IDSetNumber(&EqNP, NULL);
00695             }
00696         else if (MovementSP.s == IPS_BUSY)
00697         {
00698             
00699         for (int i=0; i < 4; i++)
00700           lastMove[i] = 0;
00701         
00702         MovementSP.s  = IPS_IDLE; 
00703         AbortSlewSP.s = IPS_OK;     
00704         EqNP.s       = IPS_IDLE;
00705         IUResetSwitches(&MovementSP);
00706         IUResetSwitches(&AbortSlewSP);
00707         IDSetSwitch(&AbortSlewSP, "Slew aborted.");
00708         IDSetSwitch(&MovementSP, NULL);
00709         IDSetNumber(&EqNP, NULL);
00710         }
00711         else
00712         {
00713             IUResetSwitches(&MovementSP);
00714             AbortSlewSP.s = IPS_OK;
00715             IDSetSwitch(&AbortSlewSP, NULL);
00716         }
00717 
00718         return;
00719     }
00720 
00721     // Alignment
00722     if (!strcmp (name, AlignmentSP.name))
00723     {
00724       if (checkPower(&AlignmentSP))
00725        return;
00726 
00727       IUResetSwitches(&AlignmentSP);
00728       IUUpdateSwitches(&AlignmentSP, states, names, n);
00729       index = getOnSwitch(&AlignmentSP);
00730 
00731       if ( ( err = setAlignmentMode(index) < 0) )
00732       {
00733          handleError(&AlignmentSP, err, "Setting alignment");
00734              return;
00735       }
00736       
00737       AlignmentSP.s = IPS_OK;
00738           IDSetSwitch (&AlignmentSP, NULL);
00739       return;
00740 
00741     }
00742 
00743         // Focus Motion
00744     if (!strcmp (name, FocusMotionSP.name))
00745     {
00746       if (checkPower(&FocusMotionSP))
00747        return;
00748 
00749       IUResetSwitches(&FocusMotionSP);
00750       
00751       // If speed is "halt"
00752       if (FocusSpeedN[0].value == 0)
00753       {
00754         FocusMotionSP.s = IPS_IDLE;
00755         IDSetSwitch(&FocusMotionSP, NULL);
00756         return;
00757       }
00758       
00759       IUUpdateSwitches(&FocusMotionSP, states, names, n);
00760       index = getOnSwitch(&FocusMotionSP);
00761       
00762       if ( ( err = setFocuserMotion(index) < 0) )
00763       {
00764          handleError(&FocusMotionSP, err, "Setting focuser speed");
00765              return;
00766       }
00767       
00768       FocusMotionSP.s = IPS_BUSY;
00769       
00770       // with a timer 
00771       if (FocusTimerN[0].value > 0)  
00772          FocusTimerNP.s  = IPS_BUSY;
00773       
00774       IDSetSwitch(&FocusMotionSP, NULL);
00775       return;
00776     }
00777 
00778     // Movement
00779     if (!strcmp (name, MovementSP.name))
00780     {
00781       if (checkPower(&MovementSP))
00782        return;
00783 
00784      index = -1;
00785      IUUpdateSwitches(&MovementSP, states, names, n);
00786      swp = IUFindSwitch(&MovementSP, names[0]);
00787      
00788      if (!swp)
00789      {
00790         abortSlew();
00791         IUResetSwitches(&MovementSP);
00792         MovementSP.s = IPS_IDLE;
00793         IDSetSwitch(&MovementSP, NULL);
00794      }
00795      
00796      if (swp == &MovementS[0]) index = 0;
00797      else if (swp == &MovementS[1]) index = 1;
00798      else if (swp == &MovementS[2]) index = 2;
00799      else index = 3;
00800      
00801      lastMove[index] = lastMove[index] == 0 ? 1 : 0;
00802      if (lastMove[index] == 0)
00803        MovementS[index].s = ISS_OFF;
00804          
00805        // North/South movement is illegal
00806        if (lastMove[LX200_NORTH] && lastMove[LX200_SOUTH])  
00807        {
00808          abortSlew();
00809           for (int i=0; i < 4; i++)
00810             lastMove[i] = 0;
00811             
00812           IUResetSwitches(&MovementSP);
00813           MovementSP.s       = IPS_IDLE;
00814           IDSetSwitch(&MovementSP, "Slew aborted.");
00815           return;
00816        }
00817        
00818        // East/West movement is illegal
00819        if (lastMove[LX200_EAST] && lastMove[LX200_WEST])    
00820        {
00821           abortSlew();
00822           for (int i=0; i < 4; i++)
00823                 lastMove[i] = 0;
00824            
00825           IUResetSwitches(&MovementSP);
00826               MovementSP.s       = IPS_IDLE;
00827           IDSetSwitch(&MovementSP, "Slew aborted.");
00828           return;
00829        }
00830           
00831           IDLog("We have switch %d \n ", index);
00832       IDLog("NORTH: %d -- WEST: %d -- EAST: %d -- SOUTH %d\n", lastMove[0], lastMove[1], lastMove[2], lastMove[3]);
00833 
00834       if (lastMove[index] == 1)
00835       {
00836             IDLog("issuing a move command\n");
00837             if ( ( err = MoveTo(index) < 0) )
00838         {
00839                  handleError(&MovementSP, err, "Setting motion direction");
00840             return;
00841         }
00842       }
00843       else
00844          HaltMovement(index);
00845 
00846           if (!lastMove[0] && !lastMove[1] && !lastMove[2] && !lastMove[3])
00847          MovementSP.s = IPS_IDLE;
00848       
00849       if (lastMove[index] == 0)
00850          IDSetSwitch(&MovementSP, "Moving toward %s aborted.", Direction[index]);
00851       else
00852       {
00853          MovementSP.s = IPS_BUSY;
00854          if (lastMove[LX200_NORTH] && lastMove[LX200_WEST])
00855            strcpy(combinedDir, "North West");
00856          else if (lastMove[LX200_NORTH] && lastMove[LX200_EAST])
00857            strcpy(combinedDir, "North East");
00858          else if (lastMove[LX200_SOUTH] && lastMove[LX200_WEST])
00859            strcpy(combinedDir, "South West");
00860          else if (lastMove[LX200_SOUTH] && lastMove[LX200_EAST])
00861            strcpy(combinedDir, "South East");
00862          else 
00863            strcpy(combinedDir, Direction[index]);
00864          
00865          IDSetSwitch(&MovementSP, "Moving %s...", combinedDir);
00866       }
00867       return;
00868     }
00869 
00870     // Tracking mode
00871     if (!strcmp (name, TrackModeSP.name))
00872     {
00873       if (checkPower(&TrackModeSP))
00874        return;
00875 
00876       IUResetSwitches(&TrackModeSP);
00877       IUUpdateSwitches(&TrackModeSP, states, names, n);
00878       trackingMode = getOnSwitch(&TrackModeSP);
00879       
00880       if ( ( err = selectAPTrackingMode(trackingMode) < 0) )
00881       {
00882              handleError(&TrackModeSP, err, "Setting tracking mode.");
00883          return;
00884       }
00885       
00886           
00887       TrackModeSP.s = IPS_OK;
00888       IDSetSwitch(&TrackModeSP, NULL);
00889       return;
00890     }
00891 
00892 }
00893 
00894 void APMount::handleError(ISwitchVectorProperty *svp, int err, const char *msg)
00895 {
00896   
00897   svp->s = IPS_ALERT;
00898   
00899   /* First check to see if the telescope is connected */
00900     if (testAP())
00901     {
00902       /* The telescope is off locally */
00903       PowerS[0].s = ISS_OFF;
00904       PowerS[1].s = ISS_ON;
00905       PowerSP.s = IPS_BUSY;
00906       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
00907       
00908       IDSetSwitch(svp, NULL);
00909       IEAddTimer(10000, retryConnection, NULL);
00910       return;
00911     }
00912     
00913    /* If the error is a time out, then the device doesn't support this property or busy*/
00914       if (err == -2)
00915       {
00916        svp->s = IPS_ALERT;
00917        IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
00918       }
00919       else
00920     /* Changing property failed, user should retry. */
00921        IDSetSwitch( svp , "%s failed.", msg);
00922        
00923        fault = true;
00924 }
00925 
00926 void APMount::handleError(INumberVectorProperty *nvp, int err, const char *msg)
00927 {
00928   
00929   nvp->s = IPS_ALERT;
00930   
00931   /* First check to see if the telescope is connected */
00932     if (testAP())
00933     {
00934       /* The telescope is off locally */
00935       PowerS[0].s = ISS_OFF;
00936       PowerS[1].s = ISS_ON;
00937       PowerSP.s = IPS_BUSY;
00938       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
00939       
00940       IDSetNumber(nvp, NULL);
00941       IEAddTimer(10000, retryConnection, NULL);
00942       return;
00943     }
00944     
00945    /* If the error is a time out, then the device doesn't support this property */
00946       if (err == -2)
00947       {
00948        nvp->s = IPS_ALERT;
00949        IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
00950       }
00951       else
00952     /* Changing property failed, user should retry. */
00953        IDSetNumber( nvp , "%s failed.", msg);
00954        
00955        fault = true;
00956 }
00957 
00958 void APMount::handleError(ITextVectorProperty *tvp, int err, const char *msg)
00959 {
00960   
00961   tvp->s = IPS_ALERT;
00962   
00963   /* First check to see if the telescope is connected */
00964     if (testAP())
00965     {
00966       /* The telescope is off locally */
00967       PowerS[0].s = ISS_OFF;
00968       PowerS[1].s = ISS_ON;
00969       PowerSP.s = IPS_BUSY;
00970       IDSetSwitch(&PowerSP, "Telescope is not responding to commands, will retry in 10 seconds.");
00971       
00972       IDSetText(tvp, NULL);
00973       IEAddTimer(10000, retryConnection, NULL);
00974       return;
00975     }
00976     
00977    /* If the error is a time out, then the device doesn't support this property */
00978       if (err == -2)
00979       {
00980        tvp->s = IPS_ALERT;
00981        IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
00982       }
00983        
00984       else
00985     /* Changing property failed, user should retry. */
00986        IDSetText( tvp , "%s failed.", msg);
00987        
00988        fault = true;
00989 }
00990 
00991  void APMount::correctFault()
00992  {
00993  
00994    fault = false;
00995    IDMessage(mydev, "Telescope is online.");
00996    
00997  }
00998 
00999 bool APMount::isTelescopeOn(void)
01000 {
01001   if (simulation) return true;
01002   
01003   return (PowerSP.sp[0].s == ISS_ON);
01004 }
01005 
01006 static void retryConnection(void * p)
01007 {
01008   p=p;
01009   
01010   if (testAP())
01011     telescope->connectionLost();
01012   else
01013     telescope->connectionResumed();
01014 }
01015 
01016 void APMount::ISPoll()
01017 {
01018         double dx, dy;
01019     int err=0;
01020     
01021     if (!isTelescopeOn())
01022      return;
01023 
01024     switch (EqNP.s)
01025     {
01026     case IPS_IDLE:
01027     getLX200RA(&currentRA);
01028     getLX200DEC(&currentDEC);
01029     
01030         if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
01031     {
01032             lastRA = currentRA;
01033         lastDEC = currentDEC;
01034         IDSetNumber (&EqNP, NULL);
01035     }
01036         break;
01037 
01038         case IPS_BUSY:
01039         getLX200RA(&currentRA);
01040         getLX200DEC(&currentDEC);
01041         dx = targetRA - currentRA;
01042         dy = targetDEC - currentDEC;
01043 
01044         IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
01045         IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
01046 
01047         // Wait until acknowledged or within threshold
01048         if (fabs(dx) <= RA_THRESHOLD && fabs(dy) <= DEC_THRESHOLD)
01049         {
01050         
01051            lastRA  = currentRA;
01052            lastDEC = currentDEC;
01053            IUResetSwitches(&OnCoordSetSP);
01054            OnCoordSetSP.s = IPS_OK;
01055            EqNP.s = IPS_OK;
01056            IDSetNumber (&EqNP, NULL);
01057 
01058         switch (currentSet)
01059         {
01060           case LX200_SLEW:
01061             OnCoordSetSP.sp[0].s = ISS_ON;
01062             IDSetSwitch (&OnCoordSetSP, "Slew is complete.");
01063             break;
01064           
01065           case LX200_TRACK:
01066             OnCoordSetSP.sp[1].s = ISS_ON;
01067             IDSetSwitch (&OnCoordSetSP, "Slew is complete. Tracking...");
01068             break;
01069           
01070           case LX200_SYNC:
01071             break;
01072         }
01073           
01074         } else
01075         IDSetNumber (&EqNP, NULL);
01076         break;
01077 
01078     case IPS_OK:
01079       
01080     if ( (err = getLX200RA(&currentRA)) < 0 || (err = getLX200DEC(&currentDEC)) < 0)
01081     {
01082       handleError(&EqNP, err, "Getting RA/DEC");
01083       return;
01084     }
01085     
01086     if (fault)
01087       correctFault();
01088     
01089     if ( (currentRA != lastRA) || (currentDEC != lastDEC))
01090     {
01091         lastRA  = currentRA;
01092         lastDEC = currentDEC;
01093         IDSetNumber (&EqNP, NULL);
01094     }
01095         break;
01096 
01097 
01098     case IPS_ALERT:
01099         break;
01100     }
01101 
01102     switch (MovementSP.s)
01103     {
01104       case IPS_IDLE:
01105        break;
01106      case IPS_BUSY:
01107        getLX200RA(&currentRA);
01108        getLX200DEC(&currentDEC);
01109        IDSetNumber (&EqNP, NULL);
01110          break;
01111      case IPS_OK:
01112        break;
01113      case IPS_ALERT:
01114        break;
01115      }
01116      
01117      switch (FocusTimerNP.s)
01118      {
01119        case IPS_IDLE:
01120          break;
01121          
01122        case IPS_BUSY:
01123         FocusTimerN[0].value--;
01124         
01125         if (FocusTimerN[0].value == 0)
01126         {
01127           
01128           if ( ( err = setFocuserSpeedMode(0) < 0) )
01129               {
01130             handleError(&FocusSpeedNP, err, "setting focuser speed mode");
01131                 IDLog("Error setting focuser speed mode\n");
01132                 return;
01133           } 
01134          
01135           
01136           FocusMotionSP.s = IPS_IDLE;
01137           FocusTimerNP.s  = IPS_OK;
01138           FocusSpeedNP.s  = IPS_OK;
01139           
01140               IUResetSwitches(&FocusMotionSP);
01141           FocusSpeedN[0].value = 0;
01142           
01143           IDSetNumber(&FocusSpeedNP, NULL);
01144           IDSetSwitch(&FocusMotionSP, NULL);
01145         }
01146         
01147         IDSetNumber(&FocusTimerNP, NULL);
01148         break;
01149         
01150        case IPS_OK:
01151         break;
01152         
01153        case IPS_ALERT:
01154         break;
01155      }
01156     
01157 
01158 }
01159 
01160 void APMount::getBasicData()
01161 {
01162 
01163   // #1 Save current time
01164   IUSaveText(&UTCT[0], timestamp());
01165   IDLog("PC UTC time is %s\n", UTCT[0].text);
01166 
01167   // #2 Make sure format is long
01168   checkLX200Format();
01169   timeFormat = LX200_24;
01170 
01171   // #3 Get current RA/DEC
01172   getLX200RA(&currentRA);
01173   getLX200DEC(&currentDEC);
01174   targetRA = currentRA;
01175   targetDEC = currentDEC;
01176 
01177   IDSetNumber (&EqNP, NULL);  
01178   updateLocation();
01179   updateTime();
01180   
01181 }
01182 
01183 int APMount::handleCoordSet()
01184 {
01185 
01186   int  err;
01187   char syncString[256];
01188   char RAStr[32], DecStr[32];
01189   double dx, dy;
01190   
01191   switch (currentSet)
01192   {
01193 
01194     // Slew
01195     case LX200_SLEW:
01196           lastSet = LX200_SLEW;
01197       if (EqNP.s == IPS_BUSY)
01198       {
01199          IDLog("Aboring Slew\n");
01200          abortSlew();
01201 
01202          // sleep for 100 mseconds
01203          usleep(100000);
01204       }
01205 
01206       if ((err = Slew()))
01207       {
01208         slewError(err);
01209         return (-1);
01210       }
01211 
01212       EqNP.s = IPS_BUSY;
01213       fs_sexa(RAStr, targetRA, 2, 3600);
01214       fs_sexa(DecStr, targetDEC, 2, 3600);
01215       IDSetNumber(&EqNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
01216       IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
01217       break;
01218 
01219      // Track
01220      case LX200_TRACK:
01221           IDLog("We're in LX200_TRACK\n");
01222           if (EqNP.s == IPS_BUSY)
01223       {
01224          IDLog("Aboring Slew\n");
01225          abortSlew();
01226 
01227          // sleep for 200 mseconds
01228          usleep(200000);
01229       }
01230 
01231       dx = fabs ( targetRA - currentRA );
01232       dy = fabs (targetDEC - currentDEC);
01233 
01234       
01235       if (dx >= TRACKING_THRESHOLD || dy >= TRACKING_THRESHOLD) 
01236       {
01237             IDLog("Exceeded Tracking threshold, will attempt to slew to the new target.\n");
01238         IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
01239             IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
01240 
01241             if ((err = Slew()))
01242         {
01243                 slewError(err);
01244                 return (-1);
01245         }
01246 
01247         fs_sexa(RAStr, targetRA, 2, 3600);
01248             fs_sexa(DecStr, targetDEC, 2, 3600);
01249         EqNP.s = IPS_BUSY;
01250         IDSetNumber(&EqNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
01251         IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
01252       }
01253       else
01254       {
01255         IDLog("Tracking called, but tracking threshold not reached yet.\n");
01256         EqNP.s = IPS_OK;
01257         EqNP.np[0].value = currentRA;
01258         EqNP.np[1].value = currentDEC;
01259 
01260         if (lastSet != LX200_TRACK)
01261           IDSetNumber(&EqNP, "Tracking...");
01262         else
01263           IDSetNumber(&EqNP, NULL);
01264       }
01265       lastSet = LX200_TRACK;
01266       break;
01267 
01268     // Sync
01269     case LX200_SYNC:
01270           lastSet = LX200_SYNC;
01271       EqNP.s = IPS_IDLE;
01272        
01273       if ( ( err = Sync(syncString) < 0) )
01274       {
01275             IDSetNumber( &EqNP , "Synchronization failed.");
01276         return (-1);
01277       }
01278 
01279       EqNP.s = IPS_OK;
01280       IDLog("Synchronization successful %s\n", syncString);
01281       IDSetNumber(&EqNP, "Synchronization successful.");
01282       break;
01283     }
01284 
01285    return (0);
01286 
01287 }
01288 
01289 int APMount::getOnSwitch(ISwitchVectorProperty *sp)
01290 {
01291  for (int i=0; i < sp->nsp ; i++)
01292      if (sp->sp[i].s == ISS_ON)
01293       return i;
01294 
01295  return -1;
01296 }
01297 
01298 
01299 int APMount::checkPower(ISwitchVectorProperty *sp)
01300 {
01301   if (simulation) return 0;
01302   
01303   if (PowerSP.s != IPS_OK)
01304   {
01305     if (!strcmp(sp->label, ""))
01306         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->name);
01307     else
01308         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->label);
01309     
01310     sp->s = IPS_IDLE;
01311     IDSetSwitch(sp, NULL);
01312     return -1;
01313   }
01314 
01315   return 0;
01316 }
01317 
01318 int APMount::checkPower(INumberVectorProperty *np)
01319 {
01320   if (simulation) return 0;
01321   
01322   if (PowerSP.s != IPS_OK)
01323   {
01324     
01325     if (!strcmp(np->label, ""))
01326         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->name);
01327     else
01328         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->label);
01329     
01330     np->s = IPS_IDLE;
01331     IDSetNumber(np, NULL);
01332     return -1;
01333   }
01334 
01335   return 0;
01336 
01337 }
01338 
01339 int APMount::checkPower(ITextVectorProperty *tp)
01340 {
01341 
01342   if (simulation) return 0;
01343   
01344   if (PowerSP.s != IPS_OK)
01345   {
01346     if (!strcmp(tp->label, ""))
01347         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->name);
01348     else
01349         IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->label);
01350     
01351     tp->s = IPS_IDLE;
01352     IDSetText(tp, NULL);
01353     return -1;
01354   }
01355 
01356   return 0;
01357 
01358 }
01359 
01360 void APMount::powerTelescope()
01361 {
01362      switch (PowerSP.sp[0].s)
01363      {
01364       case ISS_ON:  
01365     
01366         if (simulation)
01367     {
01368       PowerSP.s = IPS_OK;
01369       IDSetSwitch (&PowerSP, "Simulated telescope is online.");
01370       updateTime();
01371       return;
01372     }
01373     
01374          if (Connect(PortT[0].text))
01375      {
01376        PowerS[0].s = ISS_OFF;
01377        PowerS[1].s = ISS_ON;
01378        IDSetSwitch (&PowerSP, "Error connecting to port %s\n", PortT[0].text);
01379        return;
01380      }
01381 
01382      if (testAP())
01383      {   
01384        PowerS[0].s = ISS_OFF;
01385        PowerS[1].s = ISS_ON;
01386        IDSetSwitch (&PowerSP, "Error connecting to Telescope. Telescope is offline.");
01387        return;
01388      }
01389 
01390         IDLog("telescope test successfful\n");
01391     PowerSP.s = IPS_OK;
01392     IDSetSwitch (&PowerSP, "Telescope is online. Retrieving basic data...");
01393     getBasicData();
01394     break;
01395 
01396      case ISS_OFF:
01397          PowerS[0].s = ISS_OFF;
01398      PowerS[1].s = ISS_ON;
01399          PowerSP.s = IPS_IDLE;
01400          IDSetSwitch (&PowerSP, "Telescope is offline.");
01401      IDLog("Telescope is offline.");
01402      Disconnect();
01403      break;
01404 
01405     }
01406 
01407 }
01408 
01409 void APMount::slewError(int slewCode)
01410 {
01411     OnCoordSetSP.s = IPS_IDLE;
01412     ParkSP.s = IPS_IDLE;
01413     IDSetSwitch(&ParkSP, NULL);
01414 
01415     if (slewCode == 1)
01416     IDSetSwitch (&OnCoordSetSP, "Object below horizon.");
01417     else if (slewCode == 2)
01418     IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit.");
01419     else
01420         IDSetSwitch (&OnCoordSetSP, "Slew failed.");
01421     
01422 
01423 }
01424 
01425 void APMount::enableSimulation(bool enable)
01426 {
01427    simulation = enable;
01428    
01429    if (simulation)
01430      IDLog("Warning: Simulation is activated.\n");
01431    else
01432      IDLog("Simulation is disabled.\n");
01433 }
01434 
01435 void APMount::updateTime()
01436 {
01437 
01438   char cdate[32];
01439   double ctime;
01440   int h, m, s;
01441   int day, month, year, result;
01442   int UTC_h, UTC_month, UTC_year, UTC_day, daysInFeb;
01443   bool leapYear;
01444   
01445   tzset();
01446   
01447   UTCOffset = timezoneOffset();
01448   IDLog("Daylight: %s - TimeZone: %g\n", daylight ? "Yes" : "No", UTCOffset);
01449   
01450     
01451   if (simulation)
01452   {
01453     sprintf(UTCT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
01454     IDLog("Telescope ISO date and time: %s\n", UTCT[0].text);
01455     IDSetText(&TimeTP, NULL);
01456     return;
01457   }
01458   
01459   getLocalTime24(&ctime);
01460   getSexComponents(ctime, &h, &m, &s);
01461   
01462   UTC_h = h;
01463   
01464   if ( (result = getSDTime(&SDTimeN[0].value)) < 0)
01465     IDMessage(mydev, "Failed to retrieve siderial time from device.");
01466   
01467   getCalenderDate(cdate);
01468   
01469   result = sscanf(cdate, "%d/%d/%d", &year, &month, &day);
01470   if (result != 3) return;
01471   
01472   if (year % 4 == 0)
01473   {
01474     if (year % 100 == 0)
01475     {
01476       if (year % 400 == 0)
01477        leapYear = true;
01478       else 
01479        leapYear = false;
01480     }
01481     else
01482        leapYear = true;
01483   }
01484   else
01485        leapYear = false;
01486   
01487   daysInFeb = leapYear ? 29 : 28;
01488   
01489   UTC_year  = year; 
01490   UTC_month = month;
01491   UTC_day   = day;
01492   
01493   IDLog("day: %d - month %d - year: %d\n", day, month, year);
01494   
01495   // we'll have to convert telescope time to UTC manually starting from hour up
01496   // seems like a stupid way to do it.. oh well
01497   UTC_h = (int) UTCOffset + h;
01498   if (UTC_h < 0)
01499   {
01500    UTC_h += 24;
01501    UTC_day--;
01502   }
01503   else if (UTC_h > 24)
01504   {
01505    UTC_h -= 24;
01506    UTC_day++;
01507   }
01508   
01509   switch (UTC_month)
01510   {
01511     case 1:
01512     case 8:
01513      if (UTC_day < 1)
01514      {
01515         UTC_day = 31;
01516         UTC_month--;
01517      }
01518      else if (UTC_day > 31)
01519      {
01520        UTC_day = 1;
01521        UTC_month++;
01522      }
01523      break;
01524      
01525    case 2:
01526    if (UTC_day < 1)
01527      {
01528         UTC_day = 31;
01529         UTC_month--;
01530      }
01531      else if (UTC_day > daysInFeb)
01532      {
01533        UTC_day = 1;
01534        UTC_month++;
01535      }
01536      break;
01537      
01538   case 3:
01539      if (UTC_day < 1)
01540      {
01541         UTC_day = daysInFeb;
01542         UTC_month--;
01543      }
01544      else if (UTC_day > 31)
01545      {
01546        UTC_day = 1;
01547        UTC_month++;
01548      }
01549      break;
01550    
01551    case 4:
01552    case 6:
01553    case 9:
01554    case 11:
01555     if (UTC_day < 1)
01556      {
01557         UTC_day = 31;
01558         UTC_month--;
01559      }
01560      else if (UTC_day > 30)
01561      {
01562        UTC_day = 1;
01563        UTC_month++;
01564      }
01565      break;
01566    
01567    case 5:
01568    case 7:
01569    case 10:
01570    case 12:
01571     if (UTC_day < 1)
01572      {
01573         UTC_day = 30;
01574         UTC_month--;
01575      }
01576      else if (UTC_day > 31)
01577      {
01578        UTC_day = 1;
01579        UTC_month++;
01580      }
01581      break;
01582    
01583   }   
01584        
01585   if (UTC_month < 1)
01586   {
01587    UTC_month = 12;
01588    UTC_year--;
01589   }
01590   else if (UTC_month > 12)
01591   {
01592     UTC_month = 1;
01593     UTC_year++;
01594   }
01595   
01596   /* Format it into ISO 8601 */
01597   sprintf(UTCT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", UTC_year, UTC_month, UTC_day, UTC_h, m, s);
01598   
01599   IDLog("Local telescope time: %02d:%02d:%02d\n", h, m , s);
01600   IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value);
01601   IDLog("UTC date and time: %s\n", UTCT[0].text);
01602   
01603 
01604   // Let's send everything to the client
01605   IDSetText(&TimeTP, NULL);
01606   IDSetNumber(&SDTimeNP, NULL);
01607 
01608 }
01609 
01610 void APMount::updateLocation()
01611 {
01612 
01613  int dd = 0, mm = 0, err = 0;
01614  
01615  if ( (err = getSiteLatitude(&dd, &mm)) < 0)
01616     IDMessage(mydev, "Failed to get site latitude from device.");
01617   else
01618   {
01619     if (dd > 0)
01620         GeoNP.np[0].value = dd + mm/60.0;
01621     else
01622         GeoNP.np[0].value = dd - mm/60.0;
01623   
01624       IDLog("Astro-Physics Latitude: %d:%d\n", dd, mm);
01625       IDLog("INDI Latitude: %g\n", GeoNP.np[0].value);
01626   }
01627   
01628   if ( (err = getSiteLongitude(&dd, &mm)) < 0)
01629     IDMessage(mydev, "Failed to get site longitude from device.");
01630   else
01631   {
01632     if (dd > 0) GeoNP.np[1].value = 360.0 - (dd + mm/60.0);
01633     else GeoNP.np[1].value = (dd - mm/60.0) * -1.0;
01634     
01635     IDLog("Astro-Physics Longitude: %d:%d\n", dd, mm);
01636     IDLog("INDI Longitude: %g\n", GeoNP.np[1].value);
01637   }
01638   
01639   IDSetNumber (&GeoNP, NULL);
01640 
01641 }
01642 
01643 void APMount::connectionLost()
01644 {
01645     PowerSP.s = IPS_IDLE;
01646     IDSetSwitch(&PowerSP, "The connection to the telescope is lost.");
01647     return;
01648  
01649 }
01650 
01651 void APMount::connectionResumed()
01652 {
01653   PowerS[0].s = ISS_ON;
01654   PowerS[1].s = ISS_OFF;
01655   PowerSP.s = IPS_OK;
01656    
01657   IDSetSwitch(&PowerSP, "The connection to the telescope has been resumed.");
01658 }
01659 
01660 

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