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
00037
00038
00039
00040
00041
00042 #if !(TIMEZONE_IS_INT)
00043 static int daylight = 0;
00044 #endif
00045
00046 static inline double timezoneOffset()
00047 {
00048
00049
00050
00051
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
00070
00071
00072
00073
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
00097
00098
00099
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 *)
00138 {
00139 telescope->ISPoll();
00140 IEAddTimer (POLLMS, ISPoll, NULL);
00141 }
00142
00143 void ISNewBLOB (const char *, const char *, int *, char **, char **, char **, int )
00144 {}
00145
00146
00147
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
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
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
00270 IDDefText(&ObjectTP, NULL);
00271 IDDefNumber(&EqNP, NULL);
00272
00273 IDDefSwitch(&OnCoordSetSP, NULL);
00274 IDDefSwitch(&AbortSlewSP, NULL);
00275 IDDefSwitch(&ParkSP, NULL);
00276
00277
00278 IDDefSwitch(&TrackModeSP, NULL);
00279 IDDefSwitch(&MovementSP, NULL);
00280
00281
00282 IDDefNumber(&FocusSpeedNP, NULL);
00283 IDDefSwitch(&FocusMotionSP, NULL);
00284 IDDefNumber(&FocusTimerNP, NULL);
00285
00286
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 )
00293 {
00294 int err;
00295 struct tm *ltp = new tm;
00296 struct tm utm;
00297 time_t ltime;
00298 time (<ime);
00299 localtime_r (<ime, ltp);
00300 IText *tp;
00301
00302
00303 if (strcmp (dev, mydev))
00304 return;
00305
00306
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
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
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
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 }
00468 else
00469 {
00470 EqNP.s = IPS_IDLE;
00471 IDSetNumber(&EqNP, "RA or Dec missing or invalid");
00472 }
00473
00474 return;
00475 }
00476
00477
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
00509 if (!strcmp (name, GeoNP.name))
00510 {
00511
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
00560 if (!strcmp(name, FocusTimerNP.name))
00561 {
00562 if (checkPower(&FocusTimerNP))
00563 return;
00564
00565
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
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
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
00614 if (strcmp (mydev, dev))
00615 return;
00616
00617
00618 if (!strcmp (name, PowerSP.name))
00619 {
00620 IUResetSwitches(&PowerSP);
00621 IUUpdateSwitches(&PowerSP, states, names, n);
00622 powerTelescope();
00623 return;
00624 }
00625
00626
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
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
00650 if (index == 0)
00651 APPark();
00652 else
00653
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
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
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
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
00744 if (!strcmp (name, FocusMotionSP.name))
00745 {
00746 if (checkPower(&FocusMotionSP))
00747 return;
00748
00749 IUResetSwitches(&FocusMotionSP);
00750
00751
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
00771 if (FocusTimerN[0].value > 0)
00772 FocusTimerNP.s = IPS_BUSY;
00773
00774 IDSetSwitch(&FocusMotionSP, NULL);
00775 return;
00776 }
00777
00778
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
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
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
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
00900 if (testAP())
00901 {
00902
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
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
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
00932 if (testAP())
00933 {
00934
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
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
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
00964 if (testAP())
00965 {
00966
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
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
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(¤tRA);
01028 getLX200DEC(¤tDEC);
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(¤tRA);
01040 getLX200DEC(¤tDEC);
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
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(¤tRA)) < 0 || (err = getLX200DEC(¤tDEC)) < 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(¤tRA);
01108 getLX200DEC(¤tDEC);
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
01164 IUSaveText(&UTCT[0], timestamp());
01165 IDLog("PC UTC time is %s\n", UTCT[0].text);
01166
01167
01168 checkLX200Format();
01169 timeFormat = LX200_24;
01170
01171
01172 getLX200RA(¤tRA);
01173 getLX200DEC(¤tDEC);
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
01195 case LX200_SLEW:
01196 lastSet = LX200_SLEW;
01197 if (EqNP.s == IPS_BUSY)
01198 {
01199 IDLog("Aboring Slew\n");
01200 abortSlew();
01201
01202
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
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
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
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
01496
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
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
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