3
Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
15
You should have received a copy of the GNU Lesser General Public
16
License along with this library; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31
#include "lx200driver.h"
34
#include "lx200classic.h"
42
LX200Generic *telescope = NULL;
43
int MaxReticleFlashRate = 3;
45
/* There is _one_ binary for all LX200 drivers, but each binary is renamed
46
** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
47
** fetch from std args the binary name and ISInit will create the apporpiate
48
** device afterwards. If the binary name does not match any known devices,
49
** we simply create a generic device.
53
#define COMM_GROUP "Communication"
54
#define BASIC_GROUP "Main Control"
55
#define MOTION_GROUP "Motion Control"
56
#define DATETIME_GROUP "Date/Time"
57
#define SITE_GROUP "Site Management"
58
#define FOCUS_GROUP "Focus Control"
63
/* Simulation Parameters */
64
#define SLEWRATE 1 /* slew rate, degrees/s */
65
#define SIDRATE 0.004178 /* sidereal rate, degrees/s */
68
#define currentRA EquatorialCoordsRN[0].value
69
#define currentDEC EquatorialCoordsRN[1].value
70
#define targetRA EquatorialCoordsWN[0].value
71
#define targetDEC EquatorialCoordsWN[1].value
73
static void ISPoll(void *);
74
static void retryConnection(void *);
78
/**********************************************************************************************/
79
/************************************ GROUP: Communication ************************************/
80
/**********************************************************************************************/
82
/********************************************
84
*********************************************/
85
static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
86
ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
88
/********************************************
90
*********************************************/
91
/*wildi removed static */
92
static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}};
93
ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
95
/********************************************
96
Property: Telescope Alignment Mode
97
*********************************************/
98
static ISwitch AlignmentS [] = {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}};
99
static ISwitchVectorProperty AlignmentSw= { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0};
101
/**********************************************************************************************/
102
/************************************ GROUP: Main Control *************************************/
103
/**********************************************************************************************/
105
/********************************************
106
Property: Equatorial Coordinates JNow
108
Timeout: 120 seconds.
109
*********************************************/
110
INumber EquatorialCoordsWN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0} };
111
INumberVectorProperty EquatorialCoordsWNP= { mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial JNow", BASIC_GROUP, IP_WO, 120, IPS_IDLE, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), "", 0};
113
/********************************************
114
Property: Equatorial Coordinates JNow
116
*********************************************/
117
INumber EquatorialCoordsRN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
118
INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0};
120
/********************************************
121
Property: On Coord Set
122
Description: This property decides what happens
123
when we receive a new equatorial coord
124
value. We either track, or sync
125
to the new coordinates.
126
*********************************************/
127
static ISwitch OnCoordSetS[] = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"SYNC", "Sync", ISS_OFF, 0 , 0}};
128
ISwitchVectorProperty OnCoordSetSP= { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
130
/********************************************
131
Property: Abort telescope motion
132
*********************************************/
133
static ISwitch AbortSlewS[] = {{"ABORT", "Abort", ISS_OFF, 0, 0 }};
134
ISwitchVectorProperty AbortSlewSP= { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0};
136
/**********************************************************************************************/
137
/************************************** GROUP: Motion *****************************************/
138
/**********************************************************************************************/
140
/********************************************
142
*********************************************/
143
static ISwitch SlewModeS[] = {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}};
144
ISwitchVectorProperty SlewModeSP = { mydev, "Slew rate", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
146
/********************************************
147
Property: Tracking Mode
148
*********************************************/
149
static ISwitch TrackModeS[] = {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}};
150
static ISwitchVectorProperty TrackModeSP= { mydev, "Tracking Mode", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0};
152
/********************************************
153
Property: Tracking Frequency
154
*********************************************/
155
static INumber TrackFreqN[] = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}};
156
static INumberVectorProperty TrackingFreqNP= { mydev, "Tracking Frequency", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, TrackFreqN, NARRAY(TrackFreqN), "", 0};
158
/********************************************
159
Property: Movement (Arrow keys on handset). North/South
160
*********************************************/
161
static ISwitch MovementNSS[] = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
162
ISwitchVectorProperty MovementNSSP = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
164
/********************************************
165
Property: Movement (Arrow keys on handset). West/East
166
*********************************************/
167
static ISwitch MovementWES[] = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
168
ISwitchVectorProperty MovementWESP = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
170
/********************************************
171
Property: Slew Accuracy
172
Desciption: How close the scope have to be with
173
respect to the requested coords for
174
the tracking operation to be successull
176
*********************************************/
177
INumber SlewAccuracyN[] = {
178
{"SlewRA", "RA (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0},
179
{"SlewkDEC", "Dec (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0},
181
INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0};
183
/**********************************************************************************************/
184
/************************************** GROUP: Focus ******************************************/
185
/**********************************************************************************************/
187
/********************************************
188
Property: Focus Direction
189
*********************************************/
190
ISwitch FocusMotionS[] = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}};
191
ISwitchVectorProperty FocusMotionSP = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0};
193
/********************************************
194
Property: Focus Timer
195
*********************************************/
196
INumber FocusTimerN[] = { {"TIMER", "Timer (ms)", "%g", 0., 10000., 1000., 50., 0, 0, 0 }};
197
INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0};
199
/********************************************
201
*********************************************/
202
static ISwitch FocusModeS[] = { {"FOCUS_HALT", "Halt", ISS_ON, 0, 0},
203
{"FOCUS_SLOW", "Slow", ISS_OFF, 0, 0},
204
{"FOCUS_FAST", "Fast", ISS_OFF, 0, 0}};
205
static ISwitchVectorProperty FocusModeSP = {mydev, "FOCUS_MODE", "Mode", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusModeS, NARRAY(FocusModeS), "", 0};
207
/**********************************************************************************************/
208
/*********************************** GROUP: Date & Time ***************************************/
209
/**********************************************************************************************/
211
/********************************************
213
*********************************************/
214
static IText TimeT[] = {{"UTC", "UTC", 0, 0, 0, 0}};
215
ITextVectorProperty TimeTP = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, TimeT, NARRAY(TimeT), "", 0};
217
/********************************************
218
Property: DST Corrected UTC Offfset
219
*********************************************/
220
static INumber UTCOffsetN[] = {{"OFFSET", "Offset", "%0.3g" , -12.,12.,0.5,0., 0, 0, 0}};
221
INumberVectorProperty UTCOffsetNP = { mydev, "TIME_UTC_OFFSET", "UTC Offset", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTCOffsetN , NARRAY(UTCOffsetN), "", 0};
223
/********************************************
224
Property: Sidereal Time
225
*********************************************/
226
static INumber SDTimeN[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}};
227
INumberVectorProperty SDTimeNP = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, SDTimeN, NARRAY(SDTimeN), "", 0};
229
/**********************************************************************************************/
230
/************************************* GROUP: Sites *******************************************/
231
/**********************************************************************************************/
233
/********************************************
234
Property: Site Management
235
*********************************************/
236
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}};
237
static ISwitchVectorProperty SitesSP = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0};
239
/********************************************
241
*********************************************/
242
static IText SiteNameT[] = {{"Name", "", 0, 0, 0, 0}};
243
static ITextVectorProperty SiteNameTP = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0};
245
/********************************************
246
Property: Geographical Location
247
*********************************************/
249
static INumber geo[] = {
250
{"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
251
{"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
252
{"HEIGHT", "Height m", "%10.2f", -300., 6000., 0., 610., 0, 0, 0},
254
INumberVectorProperty geoNP = {
255
mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE,
256
geo, NARRAY(geo), "", 0};
258
/*****************************************************************************************************/
259
/**************************************** END PROPERTIES *********************************************/
260
/*****************************************************************************************************/
262
void changeLX200GenericDeviceName(const char * newName)
265
strcpy(ConnectSP.device , newName);
266
strcpy(PortTP.device , newName);
267
strcpy(AlignmentSw.device, newName);
270
strcpy(EquatorialCoordsWNP.device, newName);
271
strcpy(EquatorialCoordsRNP.device, newName);
272
strcpy(OnCoordSetSP.device , newName );
273
strcpy(AbortSlewSP.device , newName );
276
strcpy(SlewModeSP.device , newName );
277
strcpy(TrackModeSP.device , newName );
278
strcpy(TrackingFreqNP.device , newName );
279
strcpy(MovementNSSP.device , newName );
280
strcpy(MovementWESP.device , newName );
281
strcpy(SlewAccuracyNP.device, newName);
284
strcpy(FocusModeSP.device , newName );
285
strcpy(FocusMotionSP.device , newName );
286
strcpy(FocusTimerNP.device, newName);
289
strcpy(TimeTP.device , newName );
290
strcpy(UTCOffsetNP.device , newName );
291
strcpy(SDTimeNP.device , newName );
294
strcpy(SitesSP.device , newName );
295
strcpy(SiteNameTP.device , newName );
296
strcpy(geoNP.device , newName );
300
void changeAllDeviceNames(const char *newName)
302
changeLX200GenericDeviceName(newName);
303
changeLX200AutostarDeviceName(newName);
304
changeLX200AstroPhysicsDeviceName(newName);
305
changeLX200_16DeviceName(newName);
306
changeLX200ClassicDeviceName(newName);
307
changeLX200GPSDeviceName(newName);
311
/* send client definitions of all properties */
321
IUSaveText(&PortT[0], "/dev/ttyS0");
322
IUSaveText(&TimeT[0], "YYYY-MM-DDTHH:MM:SS");
324
// We need to check if UTCOffset has been set by user or not
325
UTCOffsetN[0].aux0 = (int *) malloc(sizeof(int));
326
*((int *) UTCOffsetN[0].aux0) = 0;
329
if (strstr(me, "indi_lx200classic"))
331
fprintf(stderr , "initilizaing from LX200 classic device...\n");
332
// 1. mydev = device_name
333
changeAllDeviceNames("LX200 Classic");
334
// 2. device = sub_class
335
telescope = new LX200Classic();
336
telescope->setCurrentDeviceName("LX200 Classic");
338
MaxReticleFlashRate = 3;
341
else if (strstr(me, "indi_lx200gps"))
343
fprintf(stderr , "initilizaing from LX200 GPS device...\n");
344
// 1. mydev = device_name
345
changeAllDeviceNames("LX200 GPS");
346
// 2. device = sub_class
347
telescope = new LX200GPS();
348
telescope->setCurrentDeviceName("LX200 GPS");
350
MaxReticleFlashRate = 9;
352
else if (strstr(me, "indi_lx200_16"))
355
IDLog("Initilizaing from LX200 16 device...\n");
356
// 1. mydev = device_name
357
changeAllDeviceNames("LX200 16");
358
// 2. device = sub_class
359
telescope = new LX200_16();
360
telescope->setCurrentDeviceName("LX200 16");
362
MaxReticleFlashRate = 3;
364
else if (strstr(me, "indi_lx200autostar"))
366
fprintf(stderr , "initilizaing from autostar device...\n");
368
// 1. change device name
369
changeAllDeviceNames("LX200 Autostar");
370
// 2. device = sub_class
371
telescope = new LX200Autostar();
372
telescope->setCurrentDeviceName("LX200 Autostar");
374
MaxReticleFlashRate = 9;
376
else if (strstr(me, "indi_lx200ap"))
378
fprintf(stderr , "initilizaing from ap device...\n");
380
// 1. change device name
381
changeAllDeviceNames("LX200 Astro-Physics");
382
// 2. device = sub_class
383
telescope = new LX200AstroPhysics();
384
telescope->setCurrentDeviceName("LX200 Astro-Physics");
386
MaxReticleFlashRate = 9;
388
// be nice and give them a generic device
391
telescope = new LX200Generic();
392
telescope->setCurrentDeviceName("LX200 Generic");
397
void ISGetProperties (const char *dev)
398
{ ISInit(); telescope->ISGetProperties(dev); IEAddTimer (POLLMS, ISPoll, NULL);}
399
void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
400
{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
401
void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
402
{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
403
void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
404
{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
405
void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
406
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
411
INDI_UNUSED(blobsizes);
413
INDI_UNUSED(formats);
418
void ISSnoopDevice (XMLEle *root)
420
telescope->ISSnoopDevice(root);
423
/**************************************************
424
*** LX200 Generic Implementation
425
***************************************************/
427
LX200Generic::LX200Generic()
430
trackingMode = LX200_TRACK_DEFAULT;
437
// Children call parent routines, this is the default
438
IDLog("INDI Library v%g\n", INDI_LIBV);
439
IDLog("initilizaing from generic LX200 device...\n");
440
IDLog("Driver Version: 2008-05-21\n");
442
//enableSimulation(true);
445
LX200Generic::~LX200Generic()
449
void LX200Generic::setCurrentDeviceName(const char * devName)
451
strcpy(thisDevice, devName);
454
void LX200Generic::ISGetProperties(const char *dev)
457
if (dev && strcmp (thisDevice, dev))
461
IDDefSwitch (&ConnectSP, NULL);
462
IDDefText (&PortTP, NULL);
463
IDDefSwitch (&AlignmentSw, NULL);
466
IDDefNumber (&EquatorialCoordsWNP, NULL);
467
IDDefNumber (&EquatorialCoordsRNP, NULL);
468
IDDefSwitch (&OnCoordSetSP, NULL);
469
IDDefSwitch (&AbortSlewSP, NULL);
472
IDDefNumber (&TrackingFreqNP, NULL);
473
IDDefSwitch (&SlewModeSP, NULL);
474
IDDefSwitch (&TrackModeSP, NULL);
475
IDDefSwitch (&MovementNSSP, NULL);
476
IDDefSwitch (&MovementWESP, NULL);
477
IDDefNumber (&SlewAccuracyNP, NULL);
480
IDDefSwitch(&FocusModeSP, NULL);
481
IDDefSwitch(&FocusMotionSP, NULL);
482
IDDefNumber(&FocusTimerNP, NULL);
486
IDDefText (&TimeTP, NULL);
487
IDDefNumber(&UTCOffsetNP, NULL);
490
IDDefNumber (&SDTimeNP, NULL);
493
IDDefSwitch (&SitesSP, NULL);
494
IDDefText (&SiteNameTP, NULL);
495
IDDefNumber (&geoNP, NULL);
497
/* Send the basic data to the new client if the previous client(s) are already connected. */
498
if (ConnectSP.s == IPS_OK)
503
void LX200Generic::ISSnoopDevice (XMLEle *root)
508
void LX200Generic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
513
// ignore if not ours //
514
if (strcmp (dev, thisDevice))
520
if (!strcmp(name, PortTP.name) )
523
tp = IUFindText( &PortTP, names[0] );
527
IUSaveText(&PortTP.tp[0], texts[0]);
528
IDSetText (&PortTP, NULL);
532
if (!strcmp (name, SiteNameTP.name) )
534
if (checkPower(&SiteNameTP))
537
if ( ( err = setSiteName(fd, texts[0], currentSiteNum) < 0) )
539
handleError(&SiteNameTP, err, "Setting site name");
542
SiteNameTP.s = IPS_OK;
543
tp = IUFindText(&SiteNameTP, names[0]);
544
tp->text = new char[strlen(texts[0])+1];
545
strcpy(tp->text, texts[0]);
546
IDSetText(&SiteNameTP , "Site name updated");
551
if (!strcmp (name, TimeTP.name))
553
if (checkPower(&TimeTP))
559
IUSaveText(&TimeTP.tp[0], texts[0]);
560
IDSetText(&TimeTP, "Simulated time updated.");
565
struct ln_zonedate ltm;
567
if (*((int *) UTCOffsetN[0].aux0) == 0)
570
IDSetText(&TimeTP, "You must set the UTC Offset property first.");
574
if (extractISOTime(texts[0], &utm) < 0)
577
IDSetText(&TimeTP , "Time invalid");
582
JD = ln_get_julian_day(&utm);
583
IDLog("New JD is %f\n", (float) JD);
585
ln_date_to_zonedate(&utm, <m, UTCOffsetN[0].value*3600.0);
588
if ( ( err = setLocalTime(fd, ltm.hours, ltm.minutes, ltm.seconds) < 0) )
590
handleError(&TimeTP, err, "Setting local time");
594
if (!strcmp(dev, "LX200 GPS"))
596
if ( ( err = setCalenderDate(fd, utm.days, utm.months, utm.years) < 0) )
598
handleError(&TimeTP, err, "Setting TimeT date.");
604
if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
606
handleError(&TimeTP, err, "Setting local date.");
611
// Everything Ok, save time value
612
if (IUUpdateText(&TimeTP, texts, names, n) < 0)
616
IDSetText(&TimeTP , "Time updated to %s, updating planetary data...", texts[0]);
618
// Also update telescope's sidereal time
619
getSDTime(fd, &SDTimeN[0].value);
620
IDSetNumber(&SDTimeNP, NULL);
626
void LX200Generic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
628
int h =0, m =0, s=0, err;
629
double newRA =0, newDEC =0;
631
// ignore if not ours //
632
if (strcmp (dev, thisDevice))
636
if (!strcmp (name, SlewAccuracyNP.name))
638
if (!IUUpdateNumber(&SlewAccuracyNP, values, names, n))
640
SlewAccuracyNP.s = IPS_OK;
641
IDSetNumber(&SlewAccuracyNP, NULL);
645
SlewAccuracyNP.s = IPS_ALERT;
646
IDSetNumber(&SlewAccuracyNP, "unknown error while setting tracking precision");
651
// DST Correct TimeT Offset
652
if (!strcmp (name, UTCOffsetNP.name))
654
if (strcmp(names[0], UTCOffsetN[0].name))
656
UTCOffsetNP.s = IPS_ALERT;
657
IDSetNumber( &UTCOffsetNP , "Unknown element %s for property %s.", names[0], UTCOffsetNP.label);
662
if ( ( err = setUTCOffset(fd, (values[0] * -1.0)) < 0) )
664
UTCOffsetNP.s = IPS_ALERT;
665
IDSetNumber( &UTCOffsetNP , "Setting UTC Offset failed.");
669
*((int *) UTCOffsetN[0].aux0) = 1;
670
IUUpdateNumber(&UTCOffsetNP, values, names, n);
671
UTCOffsetNP.s = IPS_OK;
672
IDSetNumber(&UTCOffsetNP, NULL);
677
if (!strcmp (name, EquatorialCoordsWNP.name))
681
if (checkPower(&EquatorialCoordsWNP))
684
for (nset = i = 0; i < n; i++)
686
INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
687
if (eqp == &EquatorialCoordsWN[0])
690
nset += newRA >= 0 && newRA <= 24.0;
691
} else if (eqp == &EquatorialCoordsWN[1])
694
nset += newDEC >= -90.0 && newDEC <= 90.0;
700
/*EquatorialCoordsWNP.s = IPS_BUSY;*/
701
char RAStr[32], DecStr[32];
703
fs_sexa(RAStr, newRA, 2, 3600);
704
fs_sexa(DecStr, newDEC, 2, 3600);
707
IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
708
IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
712
if ( (err = setObjectRA(fd, newRA)) < 0 || ( err = setObjectDEC(fd, newDEC)) < 0)
714
EquatorialCoordsWNP.s = IPS_ALERT ;
715
IDSetNumber(&EquatorialCoordsWNP, NULL);
716
handleError(&EquatorialCoordsWNP, err, "Setting RA/DEC");
719
/* wildi In principle this line is according to the discussion */
720
/* In case the telescope is slewing, we have to abort that. No status change here */
721
/* EquatorialCoordsWNP.s = IPS_OK; */
722
IDSetNumber(&EquatorialCoordsWNP, NULL);
726
if (handleCoordSet())
728
EquatorialCoordsWNP.s = IPS_ALERT;
729
IDSetNumber(&EquatorialCoordsWNP, NULL);
734
EquatorialCoordsWNP.s = IPS_ALERT;
735
IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
739
} /* end EquatorialCoordsWNP */
741
// Update Sidereal Time
742
if ( !strcmp (name, SDTimeNP.name) )
744
if (checkPower(&SDTimeNP))
748
if (values[0] < 0.0 || values[0] > 24.0)
750
SDTimeNP.s = IPS_IDLE;
751
IDSetNumber(&SDTimeNP , "Time invalid");
755
getSexComponents(values[0], &h, &m, &s);
756
IDLog("Siderial Time is %02d:%02d:%02d\n", h, m, s);
758
if ( ( err = setSDTime(fd, h, m, s) < 0) )
760
handleError(&SDTimeNP, err, "Setting siderial time");
764
SDTimeNP.np[0].value = values[0];
767
IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s);
772
// Update Geographical Location
773
if (!strcmp (name, geoNP.name))
775
// new geographic coords
776
double newLong = 0, newLat = 0;
780
if (checkPower(&geoNP))
784
for (nset = i = 0; i < n; i++)
786
INumber *geop = IUFindNumber (&geoNP, names[i]);
790
nset += newLat >= -90.0 && newLat <= 90.0;
791
} else if (geop == &geo[1])
794
nset += newLong >= 0.0 && newLong < 360.0;
802
fs_sexa (l, newLat, 3, 3600);
803
fs_sexa (L, newLong, 4, 3600);
807
if ( ( err = setSiteLongitude(fd, 360.0 - newLong) < 0) )
809
handleError(&geoNP, err, "Setting site longitude coordinates");
812
if ( ( err = setSiteLatitude(fd, newLat) < 0) )
814
handleError(&geoNP, err, "Setting site latitude coordinates");
819
geoNP.np[0].value = newLat;
820
geoNP.np[1].value = newLong;
821
snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
825
strcpy(msg, "Lat or Long missing or invalid");
827
IDSetNumber (&geoNP, "%s", msg);
832
if ( !strcmp (name, TrackingFreqNP.name) )
835
if (checkPower(&TrackingFreqNP))
838
IDLog("Trying to set track freq of: %f\n", values[0]);
840
if ( ( err = setTrackFreq(fd, values[0])) < 0)
842
handleError(&TrackingFreqNP, err, "Setting tracking frequency");
846
TrackingFreqNP.s = IPS_OK;
847
TrackingFreqNP.np[0].value = values[0];
848
IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]);
849
if (trackingMode != LX200_TRACK_MANUAL)
851
trackingMode = LX200_TRACK_MANUAL;
852
TrackModeS[0].s = ISS_OFF;
853
TrackModeS[1].s = ISS_OFF;
854
TrackModeS[2].s = ISS_ON;
855
TrackModeSP.s = IPS_OK;
856
selectTrackingMode(fd, trackingMode);
857
IDSetSwitch(&TrackModeSP, NULL);
863
if (!strcmp(name, FocusTimerNP.name))
865
if (checkPower(&FocusTimerNP))
868
// Don't update if busy
869
if (FocusTimerNP.s == IPS_BUSY)
872
IUUpdateNumber(&FocusTimerNP, values, names, n);
874
FocusTimerNP.s = IPS_OK;
876
IDSetNumber(&FocusTimerNP, NULL);
877
IDLog("Setting focus timer to %g\n", FocusTimerN[0].value);
885
void LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
890
// ignore if not ours //
891
if (strcmp (thisDevice, dev))
894
// FIRST Switch ALWAYS for power
895
if (!strcmp (name, ConnectSP.name))
897
bool connectionEstablished = (ConnectS[0].s == ISS_ON);
898
if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return;
899
if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON))
901
ConnectSP.s = IPS_OK;
902
IDSetSwitch(&ConnectSP, NULL);
910
if (!strcmp(name, OnCoordSetSP.name))
912
if (checkPower(&OnCoordSetSP))
915
if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return;
916
currentSet = getOnSwitch(&OnCoordSetSP);
917
OnCoordSetSP.s = IPS_OK;
918
IDSetSwitch(&OnCoordSetSP, NULL);
922
if (!strcmp (name, AbortSlewSP.name))
924
if (checkPower(&AbortSlewSP))
926
AbortSlewSP.s = IPS_IDLE;
927
IDSetSwitch(&AbortSlewSP, NULL);
931
IUResetSwitch(&AbortSlewSP);
932
if (abortSlew(fd) < 0)
934
AbortSlewSP.s = IPS_ALERT;
935
IDSetSwitch(&AbortSlewSP, NULL);
939
if (EquatorialCoordsWNP.s == IPS_BUSY)
941
AbortSlewSP.s = IPS_OK;
942
EquatorialCoordsWNP.s = IPS_IDLE;
943
IDSetSwitch(&AbortSlewSP, "Slew aborted.");
944
IDSetNumber(&EquatorialCoordsWNP, NULL);
946
else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
948
MovementNSSP.s = MovementWESP.s = IPS_IDLE;
950
AbortSlewSP.s = IPS_OK;
951
EquatorialCoordsWNP.s = IPS_IDLE;
952
IUResetSwitch(&MovementNSSP);
953
IUResetSwitch(&MovementWESP);
954
IUResetSwitch(&AbortSlewSP);
956
IDSetSwitch(&AbortSlewSP, "Slew aborted.");
957
IDSetSwitch(&MovementNSSP, NULL);
958
IDSetSwitch(&MovementWESP, NULL);
959
IDSetNumber(&EquatorialCoordsWNP, NULL);
963
AbortSlewSP.s = IPS_OK;
964
IDSetSwitch(&AbortSlewSP, NULL);
971
if (!strcmp (name, AlignmentSw.name))
973
if (checkPower(&AlignmentSw))
976
if (IUUpdateSwitch(&AlignmentSw, states, names, n) < 0) return;
977
index = getOnSwitch(&AlignmentSw);
979
if ( ( err = setAlignmentMode(fd, index) < 0) )
981
handleError(&AlignmentSw, err, "Setting alignment");
985
AlignmentSw.s = IPS_OK;
986
IDSetSwitch (&AlignmentSw, NULL);
992
if (!strcmp (name, SitesSP.name))
996
if (checkPower(&SitesSP))
999
if (IUUpdateSwitch(&SitesSP, states, names, n) < 0) return;
1000
currentSiteNum = getOnSwitch(&SitesSP) + 1;
1002
if ( ( err = selectSite(fd, currentSiteNum) < 0) )
1004
handleError(&SitesSP, err, "Selecting sites");
1008
if ( ( err = getSiteLatitude(fd, &dd, &mm) < 0))
1010
handleError(&SitesSP, err, "Selecting sites");
1014
if (dd > 0) geoNP.np[0].value = dd + mm / 60.0;
1015
else geoNP.np[0].value = dd - mm / 60.0;
1017
if ( ( err = getSiteLongitude(fd, &dd, &mm) < 0))
1019
handleError(&SitesSP, err, "Selecting sites");
1023
if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm / 60.0);
1024
else geoNP.np[1].value = (dd - mm / 60.0) * -1.0;
1026
getSiteName(fd, SiteNameTP.tp[0].text, currentSiteNum);
1028
IDLog("Selecting site %d\n", currentSiteNum);
1030
geoNP.s = SiteNameTP.s = SitesSP.s = IPS_OK;
1032
IDSetNumber (&geoNP, NULL);
1033
IDSetText (&SiteNameTP, NULL);
1034
IDSetSwitch (&SitesSP, NULL);
1039
if (!strcmp (name, FocusMotionSP.name))
1041
if (checkPower(&FocusMotionSP))
1044
// If mode is "halt"
1045
if (FocusModeS[0].s == ISS_ON)
1047
FocusMotionSP.s = IPS_IDLE;
1048
IDSetSwitch(&FocusMotionSP, NULL);
1052
if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return;
1053
index = getOnSwitch(&FocusMotionSP);
1055
if ( ( err = setFocuserMotion(fd, index) < 0) )
1057
handleError(&FocusMotionSP, err, "Setting focuser speed");
1061
FocusMotionSP.s = IPS_BUSY;
1064
if (FocusTimerN[0].value > 0)
1066
FocusTimerNP.s = IPS_BUSY;
1067
IEAddTimer(50, LX200Generic::updateFocusTimer, this);
1070
IDSetSwitch(&FocusMotionSP, NULL);
1075
if (!strcmp (name, SlewModeSP.name))
1077
if (checkPower(&SlewModeSP))
1080
if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return;
1081
index = getOnSwitch(&SlewModeSP);
1083
if ( ( err = setSlewMode(fd, index) < 0) )
1085
handleError(&SlewModeSP, err, "Setting slew mode");
1089
SlewModeSP.s = IPS_OK;
1090
IDSetSwitch(&SlewModeSP, NULL);
1094
// Movement (North/South)
1095
if (!strcmp (name, MovementNSSP.name))
1097
if (checkPower(&MovementNSSP))
1101
int current_move = -1;
1103
// -1 means all off previously
1104
last_move = getOnSwitch(&MovementNSSP);
1106
if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0)
1109
current_move = getOnSwitch(&MovementNSSP);
1111
// Previosuly active switch clicked again, so let's stop.
1112
if (current_move == last_move)
1114
HaltMovement(fd, (current_move == 0) ? LX200_NORTH : LX200_SOUTH);
1115
IUResetSwitch(&MovementNSSP);
1116
MovementNSSP.s = IPS_IDLE;
1117
IDSetSwitch(&MovementNSSP, NULL);
1122
IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
1125
// 0 (North) or 1 (South)
1126
last_move = current_move;
1128
// Correction for LX200 Driver: North 0 - South 3
1129
current_move = (current_move == 0) ? LX200_NORTH : LX200_SOUTH;
1131
if ( ( err = MoveTo(fd, current_move) < 0) )
1133
handleError(&MovementNSSP, err, "Setting motion direction");
1137
MovementNSSP.s = IPS_BUSY;
1138
IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == LX200_NORTH) ? "North" : "South");
1142
// Movement (West/East)
1143
if (!strcmp (name, MovementWESP.name))
1145
if (checkPower(&MovementWESP))
1149
int current_move = -1;
1151
// -1 means all off previously
1152
last_move = getOnSwitch(&MovementWESP);
1154
if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0)
1157
current_move = getOnSwitch(&MovementWESP);
1159
// Previosuly active switch clicked again, so let's stop.
1160
if (current_move == last_move)
1162
HaltMovement(fd, (current_move ==0) ? LX200_WEST : LX200_EAST);
1163
IUResetSwitch(&MovementWESP);
1164
MovementWESP.s = IPS_IDLE;
1165
IDSetSwitch(&MovementWESP, NULL);
1170
IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
1173
// 0 (West) or 1 (East)
1174
last_move = current_move;
1176
// Correction for LX200 Driver: West 1 - East 2
1177
current_move = (current_move == 0) ? LX200_WEST : LX200_EAST;
1179
if ( ( err = MoveTo(fd, current_move) < 0) )
1181
handleError(&MovementWESP, err, "Setting motion direction");
1185
MovementWESP.s = IPS_BUSY;
1186
IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == LX200_WEST) ? "West" : "East");
1191
if (!strcmp (name, TrackModeSP.name))
1193
if (checkPower(&TrackModeSP))
1196
IUResetSwitch(&TrackModeSP);
1197
IUUpdateSwitch(&TrackModeSP, states, names, n);
1198
trackingMode = getOnSwitch(&TrackModeSP);
1200
if ( ( err = selectTrackingMode(fd, trackingMode) < 0) )
1202
handleError(&TrackModeSP, err, "Setting tracking mode.");
1206
getTrackFreq(fd, &TrackFreqN[0].value);
1207
TrackModeSP.s = IPS_OK;
1208
IDSetNumber(&TrackingFreqNP, NULL);
1209
IDSetSwitch(&TrackModeSP, NULL);
1214
if (!strcmp (name, FocusModeSP.name))
1216
if (checkPower(&FocusModeSP))
1219
IUResetSwitch(&FocusModeSP);
1220
IUUpdateSwitch(&FocusModeSP, states, names, n);
1222
index = getOnSwitch(&FocusModeSP);
1224
/* disable timer and motion */
1227
IUResetSwitch(&FocusMotionSP);
1228
FocusMotionSP.s = IPS_IDLE;
1229
FocusTimerNP.s = IPS_IDLE;
1230
IDSetSwitch(&FocusMotionSP, NULL);
1231
IDSetNumber(&FocusTimerNP, NULL);
1234
setFocuserSpeedMode(fd, index);
1235
FocusModeSP.s = IPS_OK;
1236
IDSetSwitch(&FocusModeSP, NULL);
1243
void LX200Generic::handleError(ISwitchVectorProperty *svp, int err, const char *msg)
1248
/* First check to see if the telescope is connected */
1249
if (check_lx200_connection(fd))
1251
/* The telescope is off locally */
1252
ConnectS[0].s = ISS_OFF;
1253
ConnectS[1].s = ISS_ON;
1254
ConnectSP.s = IPS_BUSY;
1255
IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1257
IDSetSwitch(svp, NULL);
1258
IEAddTimer(10000, retryConnection, &fd);
1262
/* If the error is a time out, then the device doesn't support this property or busy*/
1266
IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1269
/* Changing property failed, user should retry. */
1270
IDSetSwitch( svp , "%s failed.", msg);
1275
void LX200Generic::handleError(INumberVectorProperty *nvp, int err, const char *msg)
1280
/* First check to see if the telescope is connected */
1281
if (check_lx200_connection(fd))
1283
/* The telescope is off locally */
1284
ConnectS[0].s = ISS_OFF;
1285
ConnectS[1].s = ISS_ON;
1286
ConnectSP.s = IPS_BUSY;
1287
IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1289
IDSetNumber(nvp, NULL);
1290
IEAddTimer(10000, retryConnection, &fd);
1294
/* If the error is a time out, then the device doesn't support this property */
1298
IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1301
/* Changing property failed, user should retry. */
1302
IDSetNumber( nvp , "%s failed.", msg);
1307
void LX200Generic::handleError(ITextVectorProperty *tvp, int err, const char *msg)
1312
/* First check to see if the telescope is connected */
1313
if (check_lx200_connection(fd))
1315
/* The telescope is off locally */
1316
ConnectS[0].s = ISS_OFF;
1317
ConnectS[1].s = ISS_ON;
1318
ConnectSP.s = IPS_BUSY;
1319
IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1321
IDSetText(tvp, NULL);
1322
IEAddTimer(10000, retryConnection, &fd);
1326
/* If the error is a time out, then the device doesn't support this property */
1330
IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1334
/* Changing property failed, user should retry. */
1335
IDSetText( tvp , "%s failed.", msg);
1340
void LX200Generic::correctFault()
1344
IDMessage(thisDevice, "Telescope is online.");
1348
bool LX200Generic::isTelescopeOn(void)
1350
//if (simulation) return true;
1352
return (ConnectSP.sp[0].s == ISS_ON);
1355
static void retryConnection(void * p)
1357
int fd = *( (int *) p);
1359
if (check_lx200_connection(fd))
1361
ConnectSP.s = IPS_IDLE;
1362
IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
1366
ConnectS[0].s = ISS_ON;
1367
ConnectS[1].s = ISS_OFF;
1368
ConnectSP.s = IPS_OK;
1370
IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
1374
void LX200Generic::updateFocusTimer(void *p)
1378
switch (FocusTimerNP.s)
1385
IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value);
1386
FocusTimerN[0].value-=50;
1388
if (FocusTimerN[0].value <= 0)
1390
IDLog("Focus Timer Expired\n");
1391
if ( ( err = setFocuserSpeedMode(telescope->fd, 0) < 0) )
1393
telescope->handleError(&FocusModeSP, err, "setting focuser mode");
1394
IDLog("Error setting focuser mode\n");
1399
FocusMotionSP.s = IPS_IDLE;
1400
FocusTimerNP.s = IPS_OK;
1401
FocusModeSP.s = IPS_OK;
1403
IUResetSwitch(&FocusMotionSP);
1404
IUResetSwitch(&FocusModeSP);
1405
FocusModeS[0].s = ISS_ON;
1407
IDSetSwitch(&FocusModeSP, NULL);
1408
IDSetSwitch(&FocusMotionSP, NULL);
1411
IDSetNumber(&FocusTimerNP, NULL);
1413
if (FocusTimerN[0].value > 0)
1414
IEAddTimer(50, LX200Generic::updateFocusTimer, p);
1426
void LX200Generic::ISPoll()
1429
/*static int okCounter = 3;*/
1432
if (!isTelescopeOn())
1441
if ( (err = getLX200RA(fd, ¤tRA)) < 0 || (err = getLX200DEC(fd, ¤tDEC)) < 0)
1443
EquatorialCoordsRNP.s = IPS_ALERT;
1444
IDSetNumber(&EquatorialCoordsRNP, NULL);
1445
handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
1452
EquatorialCoordsRNP.s = IPS_OK;
1454
if ( fabs(lastRA - currentRA) > (SlewAccuracyN[0].value/(60.0*15.0)) || fabs(lastDEC - currentDEC) > (SlewAccuracyN[1].value/60.0))
1457
lastDEC = currentDEC;
1458
IDSetNumber (&EquatorialCoordsRNP, NULL);
1461
switch (EquatorialCoordsWNP.s)
1467
dx = targetRA - currentRA;
1468
dy = targetDEC - currentDEC;
1470
// Wait until acknowledged or within threshold
1471
if ( fabs(dx) <= (SlewAccuracyN[0].value/(60.0*15.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0))
1474
lastDEC = currentDEC;
1476
EquatorialCoordsWNP.s = IPS_OK;
1477
IDSetNumber(&EquatorialCoordsWNP, "Slew is complete, target locked...");
1491
// wildi nothing changed in LX200Generic::mountSim
1492
void LX200Generic::mountSim ()
1494
static struct timeval ltv;
1499
/* update elapsed time since last poll, don't presume exactly POLLMS */
1500
gettimeofday (&tv, NULL);
1502
if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1505
dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6;
1509
/* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
1510
switch (EquatorialCoordsWNP.s)
1513
/* #1 State is idle, update telesocpe at sidereal rate */
1515
/* RA moves at sidereal, Dec stands still */
1516
currentRA += (SIDRATE*dt/15.);
1518
IDSetNumber(&EquatorialCoordsRNP, NULL);
1523
/* slewing - nail it when both within one pulse @ SLEWRATE */
1526
dx = targetRA - currentRA;
1530
currentRA = targetRA;
1534
currentRA += da/15.;
1536
currentRA -= da/15.;
1539
dx = targetDEC - currentDEC;
1542
currentDEC = targetDEC;
1552
EquatorialCoordsRNP.s = IPS_OK;
1553
EquatorialCoordsWNP.s = IPS_OK;
1554
IDSetNumber(&EquatorialCoordsWNP, "Now tracking");
1555
IDSetNumber(&EquatorialCoordsRNP, NULL);
1557
IDSetNumber(&EquatorialCoordsRNP, NULL);
1563
IDSetNumber(&EquatorialCoordsRNP, NULL);
1572
void LX200Generic::getBasicData()
1580
timep = gmtime (&ut);
1581
strftime (TimeTP.tp[0].text, strlen(TimeTP.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep);
1583
IDLog("PC UTC time is %s\n", TimeTP.tp[0].text);
1588
checkLX200Format(fd);
1590
if ( (err = getTimeFormat(fd, &timeFormat)) < 0)
1591
IDMessage(thisDevice, "Failed to retrieve time format from device.");
1594
timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM;
1595
// We always do 24 hours
1596
if (timeFormat != LX200_24)
1597
err = toggleTimeFormat(fd);
1600
if ( (err = getLX200RA(fd, &targetRA)) < 0 || (err = getLX200DEC(fd, &targetDEC)) < 0)
1602
EquatorialCoordsRNP.s = IPS_ALERT;
1603
IDSetNumber(&EquatorialCoordsRNP, NULL);
1604
handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
1611
// getLX200RA(fd, &targetRA);
1612
// getLX200DEC(fd, &targetDEC);
1614
EquatorialCoordsRNP.np[0].value = targetRA;
1615
EquatorialCoordsRNP.np[1].value = targetDEC;
1617
EquatorialCoordsRNP.s = IPS_OK;
1618
IDSetNumber (&EquatorialCoordsRNP, NULL);
1620
SiteNameT[0].text = new char[64];
1622
if ( (err = getSiteName(fd, SiteNameT[0].text, currentSiteNum)) < 0)
1623
IDMessage(thisDevice, "Failed to get site name from device");
1625
IDSetText (&SiteNameTP, NULL);
1627
if ( (err = getTrackFreq(fd, &TrackFreqN[0].value)) < 0)
1628
IDMessage(thisDevice, "Failed to get tracking frequency from device.");
1630
IDSetNumber (&TrackingFreqNP, NULL);
1637
int LX200Generic::handleCoordSet()
1641
char syncString[256];
1642
char RAStr[32], DecStr[32];
1648
lastSet = LX200_TRACK;
1649
if (EquatorialCoordsWNP.s == IPS_BUSY)
1652
IDLog("Aboring Slew\n");
1654
if (abortSlew(fd) < 0)
1656
AbortSlewSP.s = IPS_ALERT;
1657
IDSetSwitch(&AbortSlewSP, NULL);
1662
AbortSlewSP.s = IPS_OK;
1663
EquatorialCoordsWNP.s = IPS_IDLE;
1664
IDSetSwitch(&AbortSlewSP, "Slew aborted.");
1665
IDSetNumber(&EquatorialCoordsWNP, NULL);
1667
if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
1669
MovementNSSP.s = MovementWESP.s = IPS_IDLE;
1670
EquatorialCoordsWNP.s = IPS_IDLE;
1671
IUResetSwitch(&MovementNSSP);
1672
IUResetSwitch(&MovementWESP);
1673
IUResetSwitch(&AbortSlewSP);
1675
IDSetSwitch(&MovementNSSP, NULL);
1676
IDSetSwitch(&MovementWESP, NULL);
1679
// sleep for 100 mseconds
1683
if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
1685
IDMessage(mydev "ERROR Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
1690
EquatorialCoordsWNP.s = IPS_BUSY;
1691
fs_sexa(RAStr, targetRA, 2, 3600);
1692
fs_sexa(DecStr, targetDEC, 2, 3600);
1693
IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
1695
IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
1701
lastSet = LX200_SYNC;
1704
if ( ( err = Sync(fd, syncString) < 0) )
1706
EquatorialCoordsWNP.s = IPS_ALERT;
1707
IDSetNumber(&EquatorialCoordsWNP , "Synchronization failed.");
1711
EquatorialCoordsWNP.s = IPS_OK;
1712
IDLog("Synchronization successful %s\n", syncString);
1713
IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
1722
int LX200Generic::getOnSwitch(ISwitchVectorProperty *sp)
1724
for (int i=0; i < sp->nsp ; i++)
1725
if (sp->sp[i].s == ISS_ON)
1732
int LX200Generic::checkPower(ISwitchVectorProperty *sp)
1734
if (simulation) return 0;
1736
if (ConnectSP.s != IPS_OK)
1738
if (!strcmp(sp->label, ""))
1739
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name);
1741
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label);
1744
IDSetSwitch(sp, NULL);
1751
int LX200Generic::checkPower(INumberVectorProperty *np)
1753
if (simulation) return 0;
1755
if (ConnectSP.s != IPS_OK)
1758
if (!strcmp(np->label, ""))
1759
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name);
1761
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label);
1764
IDSetNumber(np, NULL);
1772
int LX200Generic::checkPower(ITextVectorProperty *tp)
1775
if (simulation) return 0;
1777
if (ConnectSP.s != IPS_OK)
1779
if (!strcmp(tp->label, ""))
1780
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name);
1782
IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label);
1785
IDSetText(tp, NULL);
1793
void LX200Generic::connectTelescope()
1795
switch (ConnectSP.sp[0].s)
1801
ConnectSP.s = IPS_OK;
1802
IDSetSwitch (&ConnectSP, "Simulated telescope is online.");
1807
if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
1809
ConnectS[0].s = ISS_OFF;
1810
ConnectS[1].s = ISS_ON;
1811
IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text);
1814
if (check_lx200_connection(fd))
1816
ConnectS[0].s = ISS_OFF;
1817
ConnectS[1].s = ISS_ON;
1818
IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
1823
IDLog("Telescope test successfful.\n");
1826
*((int *) UTCOffsetN[0].aux0) = 0;
1827
ConnectSP.s = IPS_OK;
1828
IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
1833
ConnectS[0].s = ISS_OFF;
1834
ConnectS[1].s = ISS_ON;
1835
ConnectSP.s = IPS_IDLE;
1836
IDSetSwitch (&ConnectSP, "Telescope is offline.");
1837
IDLog("Telescope is offline.");
1845
void LX200Generic::slewError(int slewCode)
1847
EquatorialCoordsWNP.s = IPS_ALERT;
1850
IDSetNumber(&EquatorialCoordsWNP, "Object below horizon.");
1851
else if (slewCode == 2)
1852
IDSetNumber(&EquatorialCoordsWNP, "Object below the minimum elevation limit.");
1854
IDSetNumber(&EquatorialCoordsWNP, "Slew failed.");
1858
void LX200Generic::getAlignment()
1861
if (ConnectSP.s != IPS_OK)
1864
signed char align = ACK(fd);
1867
IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment.");
1871
AlignmentS[0].s = ISS_OFF;
1872
AlignmentS[1].s = ISS_OFF;
1873
AlignmentS[2].s = ISS_OFF;
1877
case 'P': AlignmentS[0].s = ISS_ON;
1879
case 'A': AlignmentS[1].s = ISS_ON;
1881
case 'L': AlignmentS[2].s = ISS_ON;
1885
AlignmentSw.s = IPS_OK;
1886
IDSetSwitch (&AlignmentSw, NULL);
1887
IDLog("ACK success %c\n", align);
1890
void LX200Generic::enableSimulation(bool enable)
1892
simulation = enable;
1895
IDLog("Warning: Simulation is activated.\n");
1897
IDLog("Simulation is disabled.\n");
1900
void LX200Generic::updateTime()
1905
int h, m, s, lx200_utc_offset=0;
1906
int day, month, year, result;
1913
sprintf(TimeT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
1914
IDLog("Telescope ISO date and time: %s\n", TimeT[0].text);
1915
IDSetText(&TimeTP, NULL);
1919
getUTCOffset(fd, &lx200_utc_offset);
1921
// LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
1922
UTCOffsetN[0].value = lx200_utc_offset*-1;
1924
// We got a valid value for UTCOffset now
1925
*((int *) UTCOffsetN[0].aux0) = 1;
1928
IDLog("Telescope TimeT Offset: %g\n", UTCOffsetN[0].value);
1931
getLocalTime24(fd, &ctime);
1932
getSexComponents(ctime, &h, &m, &s);
1934
if ( (result = getSDTime(fd, &SDTimeN[0].value)) < 0)
1935
IDMessage(thisDevice, "Failed to retrieve siderial time from device.");
1937
getCalenderDate(fd, cdate);
1938
result = sscanf(cdate, "%d/%d/%d", &year, &month, &day);
1939
if (result != 3) return;
1941
// Let's fill in the local time
1946
ltm.tm_mon = month - 1;
1947
ltm.tm_year = year - 1900;
1950
time_epoch = mktime(<m);
1953
time_epoch -= (int) (UTCOffsetN[0].value * 60.0 * 60.0);
1955
// Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time)
1956
localtime_r(&time_epoch, &utm);
1958
/* Format it into ISO 8601 */
1959
strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm);
1960
IUSaveText(&TimeT[0], cdate);
1963
IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s);
1964
IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value);
1965
IDLog("Telescope UTC Time: %s\n", TimeT[0].text);
1968
// Let's send everything to the client
1969
IDSetText(&TimeTP, NULL);
1970
IDSetNumber(&SDTimeNP, NULL);
1971
IDSetNumber(&UTCOffsetNP, NULL);
1976
void LX200Generic::updateLocation()
1979
int dd = 0, mm = 0, err = 0;
1984
if ( (err = getSiteLatitude(fd, &dd, &mm)) < 0)
1985
IDMessage(thisDevice, "Failed to get site latitude from device.");
1989
geoNP.np[0].value = dd + mm/60.0;
1991
geoNP.np[0].value = dd - mm/60.0;
1993
IDLog("Autostar Latitude: %d:%d\n", dd, mm);
1994
IDLog("INDI Latitude: %g\n", geoNP.np[0].value);
1997
if ( (err = getSiteLongitude(fd, &dd, &mm)) < 0)
1998
IDMessage(thisDevice, "Failed to get site longitude from device.");
2001
if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm/60.0);
2002
else geoNP.np[1].value = (dd - mm/60.0) * -1.0;
2004
IDLog("Autostar Longitude: %d:%d\n", dd, mm);
2005
IDLog("INDI Longitude: %g\n", geoNP.np[1].value);
2008
IDSetNumber (&geoNP, NULL);