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
00038
00039
00040
00041
00042
00043 #if !(TIMEZONE_IS_INT)
00044 static int daylight = 0;
00045 #endif
00046
00047 static inline double timezoneOffset()
00048 {
00049
00050
00051
00052
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
00070
00071
00072
00073
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
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
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
00118
00119 INumberVectorProperty eqNum = {
00120 mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE,
00121 eq, NARRAY(eq), "", 0};
00122
00123
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
00129 static ISwitchVectorProperty AlignmentSw = { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0};
00130
00131
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
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
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
00161 static ISwitchVectorProperty SitesSw = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0};
00162
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
00180 strcpy(eqNum.device, newName);
00181 strcpy(OnCoordSetSw.device , newName );
00182 strcpy(abortSlewSw.device , newName );
00183 strcpy(ParkSP.device, newName);
00184
00185
00186 strcpy(SlewModeSw.device , newName );
00187 strcpy(TrackModeSw.device , newName );
00188 strcpy(TrackingFreq.device , newName );
00189 strcpy(MovementSw.device , newName );
00190
00191
00192 strcpy(FocusSpeedNP.device , newName );
00193 strcpy(FocusMotionSw.device , newName );
00194 strcpy(FocusTimerNP.device, newName);
00195
00196
00197 strcpy(Time.device , newName );
00198 strcpy(SDTime.device , newName );
00199
00200
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
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
00234 changeAllDeviceNames("LX200 Classic");
00235
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
00246 changeAllDeviceNames("LX200 GPS");
00247
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
00258 changeAllDeviceNames("LX200 16");
00259
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
00270 changeAllDeviceNames("LX200 Autostar");
00271
00272 telescope = new LX200Autostar();
00273 telescope->setCurrentDeviceName("LX200 Autostar");
00274
00275 MaxReticleFlashRate = 9;
00276 }
00277
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 *, const char *, int *, char **, char **, char **, int )
00296 {}
00297
00298
00299
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
00331 IDLog("initilizaing from generic LX200 device...\n");
00332 IDLog("INDI Version: 2004-02-17\n");
00333
00334
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
00350 IDDefSwitch (&PowerSP, NULL);
00351 IDDefText (&Port, NULL);
00352 IDDefSwitch (&AlignmentSw, NULL);
00353
00354
00355 IDDefNumber (&eqNum, NULL);
00356 IDDefSwitch (&OnCoordSetSw, NULL);
00357 IDDefSwitch (&abortSlewSw, NULL);
00358 IDDefSwitch (&ParkSP, NULL);
00359
00360
00361 IDDefNumber (&TrackingFreq, NULL);
00362 IDDefSwitch (&SlewModeSw, NULL);
00363 IDDefSwitch (&TrackModeSw, NULL);
00364 IDDefSwitch (&MovementSw, NULL);
00365
00366
00367 IDDefNumber(&FocusSpeedNP, NULL);
00368 IDDefSwitch(&FocusMotionSw, NULL);
00369 IDDefNumber(&FocusTimerNP, NULL);
00370
00371
00372 IDDefText (&Time, NULL);
00373 IDDefNumber (&SDTime, NULL);
00374
00375
00376 IDDefSwitch (&SitesSw, NULL);
00377 IDDefText (&SiteName, NULL);
00378 IDDefNumber (&geoNum, NULL);
00379
00380
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 (<ime);
00393 localtime_r (<ime, ltp);
00394 IText *tp;
00395
00396
00397 if (strcmp (dev, thisDevice))
00398 return;
00399
00400
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
00450
00451
00452
00453
00454
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
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
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
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
00565
00566
00567
00568
00569
00570
00571
00572 if ( (err = setObjectRA(newRA)) < 0 || ( err = setObjectDEC(newDEC)) < 0)
00573 {
00574 handleError(&eqNum, err, "Setting RA/DEC");
00575 return;
00576 }
00577
00578
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 }
00601 else
00602 {
00603 eqNum.s = IPS_IDLE;
00604 IDSetNumber(&eqNum, "RA or Dec missing or invalid");
00605 }
00606
00607 return;
00608 }
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
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
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
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
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
00777 names = names;
00778
00779
00780
00781
00782
00783
00784 if (strcmp (thisDevice, dev))
00785 return;
00786
00787
00788 if (!strcmp (name, PowerSP.name))
00789 {
00790 IUResetSwitches(&PowerSP);
00791 IUUpdateSwitches(&PowerSP, states, names, n);
00792 powerTelescope();
00793 return;
00794 }
00795
00796
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
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
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
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
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
00968 if (!strcmp (name, FocusMotionSw.name))
00969 {
00970 if (checkPower(&FocusMotionSw))
00971 return;
00972
00973 IUResetSwitches(&FocusMotionSw);
00974
00975
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
00997 if (FocusTimerN[0].value > 0)
00998 FocusTimerNP.s = IPS_BUSY;
00999
01000 IDSetSwitch(&FocusMotionSw, NULL);
01001 return;
01002 }
01003
01004
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
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
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
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
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
01148 if (testTelescope())
01149 {
01150
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
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
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
01180 if (testTelescope())
01181 {
01182
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
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
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
01212 if (testTelescope())
01213 {
01214
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
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
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
01277 int err=0;
01278
01279 if (!isTelescopeOn())
01280 return;
01281
01282 switch (eqNum.s)
01283 {
01284 case IPS_IDLE:
01285 getLX200RA(¤tRA);
01286 getLX200DEC(¤tDEC);
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(¤tRA);
01298 getLX200DEC(¤tDEC);
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
01309 if (fabs(dx) <= RA_THRESHOLD && fabs(dy) <= DEC_THRESHOLD)
01310 {
01311
01312
01313
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
01374
01375
01376
01377
01378
01379 if ( (err = getLX200RA(¤tRA)) < 0 || (err = getLX200DEC(¤tDEC)) < 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(¤tRA);
01407 getLX200DEC(¤tDEC);
01408
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
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
01529 case LX200_SLEW:
01530 lastSet = LX200_SLEW;
01531 if (eqNum.s == IPS_BUSY)
01532 {
01533 IDLog("Aboring Slew\n");
01534 abortSlew();
01535
01536
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
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
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
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
01619
01620 case LX200_PARK:
01621 if (eqNum.s == IPS_BUSY)
01622 {
01623 abortSlew();
01624
01625
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
01886
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
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
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