source: BAORadio/libindi/v1/drivers/telescope/lx200generic.cpp@ 689

Last change on this file since 689 was 490, checked in by campagne, 15 years ago

import libindi (JEC)

File size: 63.3 KB
Line 
1#if 0
2 LX200 Generic
3 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
4
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.
9
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.
14
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
18
19#endif
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <math.h>
26#include <unistd.h>
27#include <time.h>
28#include <sys/time.h>
29
30#include "indicom.h"
31#include "lx200driver.h"
32#include "lx200gps.h"
33#include "lx200ap.h"
34#include "lx200classic.h"
35
36#include <config.h>
37
38#ifdef HAVE_NOVA_H
39#include <libnova.h>
40#endif
41
42LX200Generic *telescope = NULL;
43int MaxReticleFlashRate = 3;
44
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.
50*/
51extern char* me;
52
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"
59
60#define LX200_TRACK 0
61#define LX200_SYNC 1
62
63/* Simulation Parameters */
64#define SLEWRATE 1 /* slew rate, degrees/s */
65#define SIDRATE 0.004178 /* sidereal rate, degrees/s */
66
67/* Handy Macros */
68#define currentRA EquatorialCoordsRN[0].value
69#define currentDEC EquatorialCoordsRN[1].value
70#define targetRA EquatorialCoordsWN[0].value
71#define targetDEC EquatorialCoordsWN[1].value
72
73static void ISPoll(void *);
74static void retryConnection(void *);
75
76/*INDI Propertries */
77
78/**********************************************************************************************/
79/************************************ GROUP: Communication ************************************/
80/**********************************************************************************************/
81
82/********************************************
83 Property: Connection
84*********************************************/
85static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
86ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
87
88/********************************************
89 Property: Device Port
90*********************************************/
91/*wildi removed static */
92static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}};
93ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
94
95/********************************************
96 Property: Telescope Alignment Mode
97*********************************************/
98static ISwitch AlignmentS [] = {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}};
99static ISwitchVectorProperty AlignmentSw= { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0};
100
101/**********************************************************************************************/
102/************************************ GROUP: Main Control *************************************/
103/**********************************************************************************************/
104
105/********************************************
106 Property: Equatorial Coordinates JNow
107 Perm: Transient WO.
108 Timeout: 120 seconds.
109*********************************************/
110INumber 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} };
111INumberVectorProperty EquatorialCoordsWNP= { mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial JNow", BASIC_GROUP, IP_WO, 120, IPS_IDLE, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), "", 0};
112
113/********************************************
114 Property: Equatorial Coordinates JNow
115 Perm: RO
116*********************************************/
117INumber 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}};
118INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0};
119
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*********************************************/
127static ISwitch OnCoordSetS[] = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"SYNC", "Sync", ISS_OFF, 0 , 0}};
128ISwitchVectorProperty OnCoordSetSP= { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
129
130/********************************************
131 Property: Abort telescope motion
132*********************************************/
133static ISwitch AbortSlewS[] = {{"ABORT", "Abort", ISS_OFF, 0, 0 }};
134ISwitchVectorProperty AbortSlewSP= { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0};
135
136/**********************************************************************************************/
137/************************************** GROUP: Motion *****************************************/
138/**********************************************************************************************/
139
140/********************************************
141 Property: Slew Speed
142*********************************************/
143static ISwitch SlewModeS[] = {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}};
144ISwitchVectorProperty SlewModeSP = { mydev, "Slew rate", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
145
146/********************************************
147 Property: Tracking Mode
148*********************************************/
149static ISwitch TrackModeS[] = {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}};
150static ISwitchVectorProperty TrackModeSP= { mydev, "Tracking Mode", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0};
151
152/********************************************
153 Property: Tracking Frequency
154*********************************************/
155static INumber TrackFreqN[] = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}};
156static INumberVectorProperty TrackingFreqNP= { mydev, "Tracking Frequency", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, TrackFreqN, NARRAY(TrackFreqN), "", 0};
157
158/********************************************
159 Property: Movement (Arrow keys on handset). North/South
160*********************************************/
161static ISwitch MovementNSS[] = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
162ISwitchVectorProperty MovementNSSP = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
163
164/********************************************
165 Property: Movement (Arrow keys on handset). West/East
166*********************************************/
167static ISwitch MovementWES[] = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
168ISwitchVectorProperty MovementWESP = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
169
170/********************************************
171 Property: Timed Guide movement. North/South
172*********************************************/
173static INumber GuideNSN[] = {{"TIMED_GUIDE_N", "North (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_S", "South (sec)", "%g", 0, 10, 0.001, 0, 0, 0}};
174INumberVectorProperty GuideNSNP = { mydev, "TELESCOPE_TIMED_GUIDE_NS", "Guide North/South", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideNSN, NARRAY(GuideNSN), "", 0};
175
176/********************************************
177 Property: Timed Guide movement. West/East
178*********************************************/
179static INumber GuideWEN[] = {{"TIMED_GUIDE_W", "West (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_E", "East (sec)", "%g", 0, 10, 0.001, 0, 0, 0}};
180INumberVectorProperty GuideWENP = { mydev, "TELESCOPE_TIMED_GUIDE_WE", "Guide West/East", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideWEN, NARRAY(GuideWEN), "", 0};
181
182/********************************************
183 Property: Slew Accuracy
184 Desciption: How close the scope have to be with
185 respect to the requested coords for
186 the tracking operation to be successull
187 i.e. returns OK
188*********************************************/
189INumber SlewAccuracyN[] = {
190 {"SlewRA", "RA (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0},
191 {"SlewkDEC", "Dec (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0},
192};
193INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0};
194
195/********************************************
196 Property: Use pulse-guide commands
197 Desciption: Set to on if this mount can support
198 pulse guide commands. There appears to
199 be no way to query this information from
200 the mount
201*********************************************/
202static ISwitch UsePulseCmdS[] = {{ "Off", "", ISS_ON, 0, 0} , { "On", "", ISS_OFF, 0, 0}};
203static ISwitchVectorProperty UsePulseCmdSP= { mydev, "Use Pulse Cmd", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, UsePulseCmdS, NARRAY(UsePulseCmdS), "", 0};
204
205/**********************************************************************************************/
206/************************************** GROUP: Focus ******************************************/
207/**********************************************************************************************/
208
209/********************************************
210 Property: Focus Direction
211*********************************************/
212ISwitch FocusMotionS[] = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}};
213ISwitchVectorProperty FocusMotionSP = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0};
214
215/********************************************
216 Property: Focus Timer
217*********************************************/
218INumber FocusTimerN[] = { {"TIMER", "Timer (ms)", "%g", 0., 10000., 1000., 50., 0, 0, 0 }};
219INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0};
220
221/********************************************
222 Property: Focus Mode
223*********************************************/
224static ISwitch FocusModeS[] = { {"FOCUS_HALT", "Halt", ISS_ON, 0, 0},
225 {"FOCUS_SLOW", "Slow", ISS_OFF, 0, 0},
226 {"FOCUS_FAST", "Fast", ISS_OFF, 0, 0}};
227static ISwitchVectorProperty FocusModeSP = {mydev, "FOCUS_MODE", "Mode", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusModeS, NARRAY(FocusModeS), "", 0};
228
229/**********************************************************************************************/
230/*********************************** GROUP: Date & Time ***************************************/
231/**********************************************************************************************/
232
233/********************************************
234 Property: UTC Time
235*********************************************/
236static IText TimeT[] = {{"UTC", "UTC", 0, 0, 0, 0}};
237ITextVectorProperty TimeTP = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, TimeT, NARRAY(TimeT), "", 0};
238
239/********************************************
240 Property: DST Corrected UTC Offfset
241*********************************************/
242static INumber UTCOffsetN[] = {{"OFFSET", "Offset", "%0.3g" , -12.,12.,0.5,0., 0, 0, 0}};
243INumberVectorProperty UTCOffsetNP = { mydev, "TIME_UTC_OFFSET", "UTC Offset", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTCOffsetN , NARRAY(UTCOffsetN), "", 0};
244
245/********************************************
246 Property: Sidereal Time
247*********************************************/
248static INumber SDTimeN[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}};
249INumberVectorProperty SDTimeNP = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, SDTimeN, NARRAY(SDTimeN), "", 0};
250
251/**********************************************************************************************/
252/************************************* GROUP: Sites *******************************************/
253/**********************************************************************************************/
254
255/********************************************
256 Property: Site Management
257*********************************************/
258static 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}};
259static ISwitchVectorProperty SitesSP = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0};
260
261/********************************************
262 Property: Site Name
263*********************************************/
264static IText SiteNameT[] = {{"Name", "", 0, 0, 0, 0}};
265static ITextVectorProperty SiteNameTP = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0};
266
267/********************************************
268 Property: Geographical Location
269*********************************************/
270
271static INumber geo[] = {
272 {"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
273 {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
274 {"HEIGHT", "Height m", "%10.2f", -300., 6000., 0., 610., 0, 0, 0},
275};
276INumberVectorProperty geoNP = {
277 mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE,
278 geo, NARRAY(geo), "", 0};
279
280/*****************************************************************************************************/
281/**************************************** END PROPERTIES *********************************************/
282/*****************************************************************************************************/
283
284void changeLX200GenericDeviceName(const char * newName)
285{
286 // COMM_GROUP
287 strcpy(ConnectSP.device , newName);
288 strcpy(PortTP.device , newName);
289 strcpy(AlignmentSw.device, newName);
290
291 // BASIC_GROUP
292 strcpy(EquatorialCoordsWNP.device, newName);
293 strcpy(EquatorialCoordsRNP.device, newName);
294 strcpy(OnCoordSetSP.device , newName );
295 strcpy(AbortSlewSP.device , newName );
296
297 // MOTION_GROUP
298 strcpy(SlewModeSP.device , newName );
299 strcpy(TrackModeSP.device , newName );
300 strcpy(TrackingFreqNP.device , newName );
301 strcpy(MovementNSSP.device , newName );
302 strcpy(MovementWESP.device , newName );
303 strcpy(GuideNSNP.device , newName );
304 strcpy(GuideWENP.device , newName );
305 strcpy(SlewAccuracyNP.device, newName);
306 strcpy(UsePulseCmdSP.device, newName);
307
308 // FOCUS_GROUP
309 strcpy(FocusModeSP.device , newName );
310 strcpy(FocusMotionSP.device , newName );
311 strcpy(FocusTimerNP.device, newName);
312
313 // DATETIME_GROUP
314 strcpy(TimeTP.device , newName );
315 strcpy(UTCOffsetNP.device , newName );
316 strcpy(SDTimeNP.device , newName );
317
318 // SITE_GROUP
319 strcpy(SitesSP.device , newName );
320 strcpy(SiteNameTP.device , newName );
321 strcpy(geoNP.device , newName );
322
323}
324
325void changeAllDeviceNames(const char *newName)
326{
327 changeLX200GenericDeviceName(newName);
328 changeLX200AutostarDeviceName(newName);
329 changeLX200AstroPhysicsDeviceName(newName);
330 changeLX200_16DeviceName(newName);
331 changeLX200ClassicDeviceName(newName);
332 changeLX200GPSDeviceName(newName);
333}
334
335
336/* send client definitions of all properties */
337void ISInit()
338{
339 static int isInit=0;
340
341 if (isInit)
342 return;
343
344 isInit = 1;
345
346 IUSaveText(&PortT[0], "/dev/ttyS0");
347 IUSaveText(&TimeT[0], "YYYY-MM-DDTHH:MM:SS");
348
349 // We need to check if UTCOffset has been set by user or not
350 UTCOffsetN[0].aux0 = (int *) malloc(sizeof(int));
351 *((int *) UTCOffsetN[0].aux0) = 0;
352
353
354 if (strstr(me, "indi_lx200classic"))
355 {
356 fprintf(stderr , "initilizaing from LX200 classic device...\n");
357 // 1. mydev = device_name
358 changeAllDeviceNames("LX200 Classic");
359 // 2. device = sub_class
360 telescope = new LX200Classic();
361 telescope->setCurrentDeviceName("LX200 Classic");
362
363 MaxReticleFlashRate = 3;
364 }
365
366 else if (strstr(me, "indi_lx200gps"))
367 {
368 fprintf(stderr , "initilizaing from LX200 GPS device...\n");
369 // 1. mydev = device_name
370 changeAllDeviceNames("LX200 GPS");
371 // 2. device = sub_class
372 telescope = new LX200GPS();
373 telescope->setCurrentDeviceName("LX200 GPS");
374
375 MaxReticleFlashRate = 9;
376 }
377 else if (strstr(me, "indi_lx200_16"))
378 {
379
380 IDLog("Initilizaing from LX200 16 device...\n");
381 // 1. mydev = device_name
382 changeAllDeviceNames("LX200 16");
383 // 2. device = sub_class
384 telescope = new LX200_16();
385 telescope->setCurrentDeviceName("LX200 16");
386
387 MaxReticleFlashRate = 3;
388 }
389 else if (strstr(me, "indi_lx200autostar"))
390 {
391 fprintf(stderr , "initilizaing from autostar device...\n");
392
393 // 1. change device name
394 changeAllDeviceNames("LX200 Autostar");
395 // 2. device = sub_class
396 telescope = new LX200Autostar();
397 telescope->setCurrentDeviceName("LX200 Autostar");
398
399 MaxReticleFlashRate = 9;
400 }
401 else if (strstr(me, "indi_lx200ap"))
402 {
403 fprintf(stderr , "initilizaing from ap device...\n");
404
405 // 1. change device name
406 changeAllDeviceNames("LX200 Astro-Physics");
407 // 2. device = sub_class
408 telescope = new LX200AstroPhysics();
409 telescope->setCurrentDeviceName("LX200 Astro-Physics");
410
411 MaxReticleFlashRate = 9;
412 }
413 // be nice and give them a generic device
414 else
415 {
416 telescope = new LX200Generic();
417 telescope->setCurrentDeviceName("LX200 Generic");
418 }
419
420}
421
422void ISGetProperties (const char *dev)
423{ ISInit(); telescope->ISGetProperties(dev); IEAddTimer (POLLMS, ISPoll, NULL);}
424void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
425{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
426void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
427{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
428void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
429{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
430void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
431void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
432{
433 INDI_UNUSED(dev);
434 INDI_UNUSED(name);
435 INDI_UNUSED(sizes);
436 INDI_UNUSED(blobsizes);
437 INDI_UNUSED(blobs);
438 INDI_UNUSED(formats);
439 INDI_UNUSED(names);
440 INDI_UNUSED(n);
441}
442
443void ISSnoopDevice (XMLEle *root)
444{
445 telescope->ISSnoopDevice(root);
446}
447
448/**************************************************
449*** LX200 Generic Implementation
450***************************************************/
451
452LX200Generic::LX200Generic()
453{
454 currentSiteNum = 1;
455 trackingMode = LX200_TRACK_DEFAULT;
456 lastSet = -1;
457 fault = false;
458 simulation = false;
459 currentSet = 0;
460 fd = -1;
461 GuideNSTID = 0;
462 GuideWETID = 0;
463
464 // Children call parent routines, this is the default
465 IDLog("INDI Library v%g\n", INDI_LIBV);
466 IDLog("initilizaing from generic LX200 device...\n");
467 IDLog("Driver Version: 2008-05-21\n");
468
469 //enableSimulation(true);
470}
471
472LX200Generic::~LX200Generic()
473{
474}
475
476void LX200Generic::setCurrentDeviceName(const char * devName)
477{
478 strcpy(thisDevice, devName);
479}
480
481void LX200Generic::ISGetProperties(const char *dev)
482{
483
484 if (dev && strcmp (thisDevice, dev))
485 return;
486
487 // COMM_GROUP
488 IDDefSwitch (&ConnectSP, NULL);
489 IDDefText (&PortTP, NULL);
490 IDDefSwitch (&AlignmentSw, NULL);
491
492 // BASIC_GROUP
493 IDDefNumber (&EquatorialCoordsWNP, NULL);
494 IDDefNumber (&EquatorialCoordsRNP, NULL);
495 IDDefSwitch (&OnCoordSetSP, NULL);
496 IDDefSwitch (&AbortSlewSP, NULL);
497
498 // MOTION_GROUP
499 IDDefNumber (&TrackingFreqNP, NULL);
500 IDDefSwitch (&SlewModeSP, NULL);
501 IDDefSwitch (&TrackModeSP, NULL);
502 IDDefSwitch (&MovementNSSP, NULL);
503 IDDefSwitch (&MovementWESP, NULL);
504 IDDefNumber (&GuideNSNP, NULL );
505 IDDefNumber (&GuideWENP, NULL );
506 IDDefNumber (&SlewAccuracyNP, NULL);
507 IDDefSwitch (&UsePulseCmdSP, NULL);
508
509 // FOCUS_GROUP
510 IDDefSwitch(&FocusModeSP, NULL);
511 IDDefSwitch(&FocusMotionSP, NULL);
512 IDDefNumber(&FocusTimerNP, NULL);
513
514 // DATETIME_GROUP
515 #ifdef HAVE_NOVA_H
516 IDDefText (&TimeTP, NULL);
517 IDDefNumber(&UTCOffsetNP, NULL);
518 #endif
519
520 IDDefNumber (&SDTimeNP, NULL);
521
522 // SITE_GROUP
523 IDDefSwitch (&SitesSP, NULL);
524 IDDefText (&SiteNameTP, NULL);
525 IDDefNumber (&geoNP, NULL);
526
527 /* Send the basic data to the new client if the previous client(s) are already connected. */
528 if (ConnectSP.s == IPS_OK)
529 getBasicData();
530
531}
532
533void LX200Generic::ISSnoopDevice (XMLEle *root)
534{
535 INDI_UNUSED(root);
536}
537
538void LX200Generic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
539{
540 int err;
541 IText *tp;
542
543 // ignore if not ours //
544 if (strcmp (dev, thisDevice))
545 return;
546
547 // suppress warning
548 n=n;
549
550 if (!strcmp(name, PortTP.name) )
551 {
552 PortTP.s = IPS_OK;
553 tp = IUFindText( &PortTP, names[0] );
554 if (!tp)
555 return;
556
557 IUSaveText(&PortTP.tp[0], texts[0]);
558 IDSetText (&PortTP, NULL);
559 return;
560 }
561
562 if (!strcmp (name, SiteNameTP.name) )
563 {
564 if (checkPower(&SiteNameTP))
565 return;
566
567 if ( ( err = setSiteName(fd, texts[0], currentSiteNum) < 0) )
568 {
569 handleError(&SiteNameTP, err, "Setting site name");
570 return;
571 }
572 SiteNameTP.s = IPS_OK;
573 tp = IUFindText(&SiteNameTP, names[0]);
574 tp->text = new char[strlen(texts[0])+1];
575 strcpy(tp->text, texts[0]);
576 IDSetText(&SiteNameTP , "Site name updated");
577 return;
578 }
579
580 #ifdef HAVE_NOVA_H
581 if (!strcmp (name, TimeTP.name))
582 {
583 if (checkPower(&TimeTP))
584 return;
585
586 if (simulation)
587 {
588 TimeTP.s = IPS_OK;
589 IUSaveText(&TimeTP.tp[0], texts[0]);
590 IDSetText(&TimeTP, "Simulated time updated.");
591 return;
592 }
593
594 struct ln_date utm;
595 struct ln_zonedate ltm;
596
597 if (*((int *) UTCOffsetN[0].aux0) == 0)
598 {
599 TimeTP.s = IPS_IDLE;
600 IDSetText(&TimeTP, "You must set the UTC Offset property first.");
601 return;
602 }
603
604 if (extractISOTime(texts[0], &utm) < 0)
605 {
606 TimeTP.s = IPS_IDLE;
607 IDSetText(&TimeTP , "Time invalid");
608 return;
609 }
610
611 // update JD
612 JD = ln_get_julian_day(&utm);
613 IDLog("New JD is %f\n", (float) JD);
614
615 ln_date_to_zonedate(&utm, &ltm, UTCOffsetN[0].value*3600.0);
616
617 // Set Local Time
618 if ( ( err = setLocalTime(fd, ltm.hours, ltm.minutes, ltm.seconds) < 0) )
619 {
620 handleError(&TimeTP, err, "Setting local time");
621 return;
622 }
623
624 if (!strcmp(dev, "LX200 GPS"))
625 {
626 if ( ( err = setCalenderDate(fd, utm.days, utm.months, utm.years) < 0) )
627 {
628 handleError(&TimeTP, err, "Setting TimeT date.");
629 return;
630 }
631 }
632 else
633 {
634 if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
635 {
636 handleError(&TimeTP, err, "Setting local date.");
637 return;
638 }
639 }
640
641 // Everything Ok, save time value
642 if (IUUpdateText(&TimeTP, texts, names, n) < 0)
643 return;
644
645 TimeTP.s = IPS_OK;
646 IDSetText(&TimeTP , "Time updated to %s, updating planetary data...", texts[0]);
647
648 // Also update telescope's sidereal time
649 getSDTime(fd, &SDTimeN[0].value);
650 IDSetNumber(&SDTimeNP, NULL);
651 }
652 #endif
653}
654
655
656void LX200Generic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
657{
658 int h =0, m =0, s=0, err;
659 double newRA =0, newDEC =0;
660
661 // ignore if not ours //
662 if (strcmp (dev, thisDevice))
663 return;
664
665 // Slewing Accuracy
666 if (!strcmp (name, SlewAccuracyNP.name))
667 {
668 if (!IUUpdateNumber(&SlewAccuracyNP, values, names, n))
669 {
670 SlewAccuracyNP.s = IPS_OK;
671 IDSetNumber(&SlewAccuracyNP, NULL);
672 return;
673 }
674
675 SlewAccuracyNP.s = IPS_ALERT;
676 IDSetNumber(&SlewAccuracyNP, "unknown error while setting tracking precision");
677 return;
678 }
679
680 #ifdef HAVE_NOVA_H
681 // DST Correct TimeT Offset
682 if (!strcmp (name, UTCOffsetNP.name))
683 {
684 if (strcmp(names[0], UTCOffsetN[0].name))
685 {
686 UTCOffsetNP.s = IPS_ALERT;
687 IDSetNumber( &UTCOffsetNP , "Unknown element %s for property %s.", names[0], UTCOffsetNP.label);
688 return;
689 }
690
691 if (!simulation)
692 if ( ( err = setUTCOffset(fd, (values[0] * -1.0)) < 0) )
693 {
694 UTCOffsetNP.s = IPS_ALERT;
695 IDSetNumber( &UTCOffsetNP , "Setting UTC Offset failed.");
696 return;
697 }
698
699 *((int *) UTCOffsetN[0].aux0) = 1;
700 IUUpdateNumber(&UTCOffsetNP, values, names, n);
701 UTCOffsetNP.s = IPS_OK;
702 IDSetNumber(&UTCOffsetNP, NULL);
703 return;
704 }
705 #endif
706
707 if (!strcmp (name, EquatorialCoordsWNP.name))
708 {
709 int i=0, nset=0;
710
711 if (checkPower(&EquatorialCoordsWNP))
712 return;
713
714 for (nset = i = 0; i < n; i++)
715 {
716 INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
717 if (eqp == &EquatorialCoordsWN[0])
718 {
719 newRA = values[i];
720 nset += newRA >= 0 && newRA <= 24.0;
721 } else if (eqp == &EquatorialCoordsWN[1])
722 {
723 newDEC = values[i];
724 nset += newDEC >= -90.0 && newDEC <= 90.0;
725 }
726 }
727
728 if (nset == 2)
729 {
730 /*EquatorialCoordsWNP.s = IPS_BUSY;*/
731 char RAStr[32], DecStr[32];
732
733 fs_sexa(RAStr, newRA, 2, 3600);
734 fs_sexa(DecStr, newDEC, 2, 3600);
735
736 #ifdef INDI_DEBUG
737 IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
738 IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
739 #endif
740
741 if (!simulation)
742 if ( (err = setObjectRA(fd, newRA)) < 0 || ( err = setObjectDEC(fd, newDEC)) < 0)
743 {
744 EquatorialCoordsWNP.s = IPS_ALERT ;
745 IDSetNumber(&EquatorialCoordsWNP, NULL);
746 handleError(&EquatorialCoordsWNP, err, "Setting RA/DEC");
747 return;
748 }
749 /* wildi In principle this line is according to the discussion */
750 /* In case the telescope is slewing, we have to abort that. No status change here */
751 /* EquatorialCoordsWNP.s = IPS_OK; */
752 IDSetNumber(&EquatorialCoordsWNP, NULL);
753 targetRA = newRA;
754 targetDEC = newDEC;
755
756 if (handleCoordSet())
757 {
758 EquatorialCoordsWNP.s = IPS_ALERT;
759 IDSetNumber(&EquatorialCoordsWNP, NULL);
760 }
761 } // end nset
762 else
763 {
764 EquatorialCoordsWNP.s = IPS_ALERT;
765 IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
766 }
767
768 return;
769 } /* end EquatorialCoordsWNP */
770
771 // Update Sidereal Time
772 if ( !strcmp (name, SDTimeNP.name) )
773 {
774 if (checkPower(&SDTimeNP))
775 return;
776
777
778 if (values[0] < 0.0 || values[0] > 24.0)
779 {
780 SDTimeNP.s = IPS_IDLE;
781 IDSetNumber(&SDTimeNP , "Time invalid");
782 return;
783 }
784
785 getSexComponents(values[0], &h, &m, &s);
786 IDLog("Siderial Time is %02d:%02d:%02d\n", h, m, s);
787
788 if ( ( err = setSDTime(fd, h, m, s) < 0) )
789 {
790 handleError(&SDTimeNP, err, "Setting siderial time");
791 return;
792 }
793
794 SDTimeNP.np[0].value = values[0];
795 SDTimeNP.s = IPS_OK;
796
797 IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s);
798
799 return;
800 }
801
802 // Update Geographical Location
803 if (!strcmp (name, geoNP.name))
804 {
805 // new geographic coords
806 double newLong = 0, newLat = 0;
807 int i, nset;
808 char msg[128];
809
810 if (checkPower(&geoNP))
811 return;
812
813
814 for (nset = i = 0; i < n; i++)
815 {
816 INumber *geop = IUFindNumber (&geoNP, names[i]);
817 if (geop == &geo[0])
818 {
819 newLat = values[i];
820 nset += newLat >= -90.0 && newLat <= 90.0;
821 } else if (geop == &geo[1])
822 {
823 newLong = values[i];
824 nset += newLong >= 0.0 && newLong < 360.0;
825 }
826 }
827
828 if (nset == 2)
829 {
830 char l[32], L[32];
831 geoNP.s = IPS_OK;
832 fs_sexa (l, newLat, 3, 3600);
833 fs_sexa (L, newLong, 4, 3600);
834
835 if (!simulation)
836 {
837 if ( ( err = setSiteLongitude(fd, 360.0 - newLong) < 0) )
838 {
839 handleError(&geoNP, err, "Setting site longitude coordinates");
840 return;
841 }
842 if ( ( err = setSiteLatitude(fd, newLat) < 0) )
843 {
844 handleError(&geoNP, err, "Setting site latitude coordinates");
845 return;
846 }
847 }
848
849 geoNP.np[0].value = newLat;
850 geoNP.np[1].value = newLong;
851 snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
852 } else
853 {
854 geoNP.s = IPS_IDLE;
855 strcpy(msg, "Lat or Long missing or invalid");
856 }
857 IDSetNumber (&geoNP, "%s", msg);
858 return;
859 }
860
861 // Update Frequency
862 if ( !strcmp (name, TrackingFreqNP.name) )
863 {
864
865 if (checkPower(&TrackingFreqNP))
866 return;
867
868 IDLog("Trying to set track freq of: %f\n", values[0]);
869
870 if ( ( err = setTrackFreq(fd, values[0])) < 0)
871 {
872 handleError(&TrackingFreqNP, err, "Setting tracking frequency");
873 return;
874 }
875
876 TrackingFreqNP.s = IPS_OK;
877 TrackingFreqNP.np[0].value = values[0];
878 IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]);
879 if (trackingMode != LX200_TRACK_MANUAL)
880 {
881 trackingMode = LX200_TRACK_MANUAL;
882 TrackModeS[0].s = ISS_OFF;
883 TrackModeS[1].s = ISS_OFF;
884 TrackModeS[2].s = ISS_ON;
885 TrackModeSP.s = IPS_OK;
886 selectTrackingMode(fd, trackingMode);
887 IDSetSwitch(&TrackModeSP, NULL);
888 }
889
890 return;
891 }
892
893 if (!strcmp(name, FocusTimerNP.name))
894 {
895 if (checkPower(&FocusTimerNP))
896 return;
897
898 // Don't update if busy
899 if (FocusTimerNP.s == IPS_BUSY)
900 return;
901
902 IUUpdateNumber(&FocusTimerNP, values, names, n);
903
904 FocusTimerNP.s = IPS_OK;
905
906 IDSetNumber(&FocusTimerNP, NULL);
907 IDLog("Setting focus timer to %g\n", FocusTimerN[0].value);
908
909 return;
910
911 }
912
913 if (!strcmp(name, GuideNSNP.name))
914 {
915 long direction;
916 int duration_msec;
917 int use_pulse_cmd;
918 if (checkPower(&GuideNSNP))
919 return;
920 if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
921 {
922 handleError(&GuideNSNP, err, "Can't guide while moving");
923 return;
924 }
925 if (GuideNSNP.s == IPS_BUSY)
926 {
927 // Already guiding so stop before restarting timer
928 HaltMovement(fd, LX200_NORTH);
929 HaltMovement(fd, LX200_SOUTH);
930 }
931 if (GuideNSTID) {
932 IERmTimer(GuideNSTID);
933 GuideNSTID = 0;
934 }
935 IUUpdateNumber(&GuideNSNP, values, names, n);
936
937 if (GuideNSNP.np[0].value > 0) {
938 duration_msec = GuideNSNP.np[0].value * 1000;
939 direction = LX200_NORTH;
940 } else {
941 duration_msec = GuideNSNP.np[1].value * 1000;
942 direction = LX200_SOUTH;
943 }
944 if (duration_msec <= 0) {
945 GuideNSNP.s = IPS_IDLE;
946 IDSetNumber (&GuideNSNP, NULL);
947 return;
948 }
949 use_pulse_cmd = getOnSwitch(&UsePulseCmdSP);
950 // fprintf(stderr, "Using %s mode to move %dmsec %s\n",
951 // use_pulse_cmd ? "Pulse" : "Legacy",
952 // duration_msec, direction == LX200_NORTH ? "North" : "South");
953 if (use_pulse_cmd) {
954 SendPulseCmd(fd, direction, duration_msec);
955 } else {
956 if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) )
957 {
958 handleError(&SlewModeSP, err, "Setting slew mode");
959 return;
960 }
961 MoveTo(fd, direction);
962 }
963 GuideNSTID = IEAddTimer (duration_msec, guideTimeout, (void *)direction);
964 GuideNSNP.s = IPS_BUSY;
965 IDSetNumber(&GuideNSNP, NULL);
966 }
967 if (!strcmp(name, GuideWENP.name))
968 {
969 long direction;
970 int duration_msec;
971 int use_pulse_cmd;
972
973 if (checkPower(&GuideWENP))
974 return;
975 if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
976 {
977 handleError(&GuideWENP, err, "Can't guide while moving");
978 return;
979 }
980 if (GuideWENP.s == IPS_BUSY)
981 {
982 // Already guiding so stop before restarting timer
983 HaltMovement(fd, LX200_WEST);
984 HaltMovement(fd, LX200_EAST);
985 }
986 if (GuideWETID) {
987 IERmTimer(GuideWETID);
988 GuideWETID = 0;
989 }
990 IUUpdateNumber(&GuideWENP, values, names, n);
991
992 if (GuideWENP.np[0].value > 0) {
993 duration_msec = GuideWENP.np[0].value * 1000;
994 direction = LX200_WEST;
995 } else {
996 duration_msec = GuideWENP.np[1].value * 1000;
997 direction = LX200_EAST;
998 }
999 if (duration_msec <= 0) {
1000 GuideWENP.s = IPS_IDLE;
1001 IDSetNumber (&GuideWENP, NULL);
1002 return;
1003 }
1004 use_pulse_cmd = getOnSwitch(&UsePulseCmdSP);
1005 // fprintf(stderr, "Using %s mode to move %dmsec %s\n",
1006 // use_pulse_cmd ? "Pulse" : "Legacy",
1007 // duration_msec, direction == LX200_WEST ? "West" : "East");
1008
1009 if (use_pulse_cmd) {
1010 SendPulseCmd(fd, direction, duration_msec);
1011 } else {
1012 if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) )
1013 {
1014 handleError(&SlewModeSP, err, "Setting slew mode");
1015 return;
1016 }
1017 MoveTo(fd, direction);
1018 }
1019 GuideWETID = IEAddTimer (duration_msec, guideTimeout, (void *)direction);
1020 GuideWENP.s = IPS_BUSY;
1021 IDSetNumber(&GuideWENP, NULL);
1022 }
1023}
1024
1025void LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
1026{
1027 int err=0, index=0;
1028 INDI_UNUSED(names);
1029
1030 // ignore if not ours //
1031 if (strcmp (thisDevice, dev))
1032 return;
1033
1034 // FIRST Switch ALWAYS for power
1035 if (!strcmp (name, ConnectSP.name))
1036 {
1037 bool connectionEstablished = (ConnectS[0].s == ISS_ON);
1038 if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return;
1039 if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON))
1040 {
1041 ConnectSP.s = IPS_OK;
1042 IDSetSwitch(&ConnectSP, NULL);
1043 return;
1044 }
1045 connectTelescope();
1046 return;
1047 }
1048
1049 // Coord set
1050 if (!strcmp(name, OnCoordSetSP.name))
1051 {
1052 if (checkPower(&OnCoordSetSP))
1053 return;
1054
1055 if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return;
1056 currentSet = getOnSwitch(&OnCoordSetSP);
1057 OnCoordSetSP.s = IPS_OK;
1058 IDSetSwitch(&OnCoordSetSP, NULL);
1059 }
1060
1061 // Abort Slew
1062 if (!strcmp (name, AbortSlewSP.name))
1063 {
1064 if (checkPower(&AbortSlewSP))
1065 {
1066 AbortSlewSP.s = IPS_IDLE;
1067 IDSetSwitch(&AbortSlewSP, NULL);
1068 return;
1069 }
1070
1071 IUResetSwitch(&AbortSlewSP);
1072 if (abortSlew(fd) < 0)
1073 {
1074 AbortSlewSP.s = IPS_ALERT;
1075 IDSetSwitch(&AbortSlewSP, NULL);
1076 return;
1077 }
1078
1079 if (EquatorialCoordsWNP.s == IPS_BUSY)
1080 {
1081 AbortSlewSP.s = IPS_OK;
1082 EquatorialCoordsWNP.s = IPS_IDLE;
1083 IDSetSwitch(&AbortSlewSP, "Slew aborted.");
1084 IDSetNumber(&EquatorialCoordsWNP, NULL);
1085 }
1086 else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
1087 {
1088 MovementNSSP.s = MovementWESP.s = IPS_IDLE;
1089
1090 AbortSlewSP.s = IPS_OK;
1091 EquatorialCoordsWNP.s = IPS_IDLE;
1092 IUResetSwitch(&MovementNSSP);
1093 IUResetSwitch(&MovementWESP);
1094 IUResetSwitch(&AbortSlewSP);
1095
1096 IDSetSwitch(&AbortSlewSP, "Slew aborted.");
1097 IDSetSwitch(&MovementNSSP, NULL);
1098 IDSetSwitch(&MovementWESP, NULL);
1099 IDSetNumber(&EquatorialCoordsWNP, NULL);
1100 }
1101 else if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
1102 {
1103 GuideNSNP.s = GuideWENP.s = IPS_IDLE;
1104 GuideNSN[0].value = GuideNSN[1].value = 0.0;
1105 GuideWEN[0].value = GuideWEN[1].value = 0.0;
1106 if (GuideNSTID) {
1107 IERmTimer(GuideNSTID);
1108 GuideNSTID = 0;
1109 }
1110 if (GuideWETID) {
1111 IERmTimer(GuideWETID);
1112 GuideNSTID = 0;
1113 }
1114
1115 AbortSlewSP.s = IPS_OK;
1116 EquatorialCoordsWNP.s = IPS_IDLE;
1117 IUResetSwitch(&AbortSlewSP);
1118
1119 IDSetSwitch(&AbortSlewSP, "Guide aborted.");
1120 IDSetNumber(&GuideNSNP, NULL);
1121 IDSetNumber(&GuideWENP, NULL);
1122 IDSetNumber(&EquatorialCoordsWNP, NULL);
1123 }
1124 else
1125 {
1126 AbortSlewSP.s = IPS_OK;
1127 IDSetSwitch(&AbortSlewSP, NULL);
1128 }
1129
1130 return;
1131 }
1132
1133 // Alignment
1134 if (!strcmp (name, AlignmentSw.name))
1135 {
1136 if (checkPower(&AlignmentSw))
1137 return;
1138
1139 if (IUUpdateSwitch(&AlignmentSw, states, names, n) < 0) return;
1140 index = getOnSwitch(&AlignmentSw);
1141
1142 if ( ( err = setAlignmentMode(fd, index) < 0) )
1143 {
1144 handleError(&AlignmentSw, err, "Setting alignment");
1145 return;
1146 }
1147
1148 AlignmentSw.s = IPS_OK;
1149 IDSetSwitch (&AlignmentSw, NULL);
1150 return;
1151
1152 }
1153
1154 // Sites
1155 if (!strcmp (name, SitesSP.name))
1156 {
1157 int dd=0, mm=0;
1158
1159 if (checkPower(&SitesSP))
1160 return;
1161
1162 if (IUUpdateSwitch(&SitesSP, states, names, n) < 0) return;
1163 currentSiteNum = getOnSwitch(&SitesSP) + 1;
1164
1165 if ( ( err = selectSite(fd, currentSiteNum) < 0) )
1166 {
1167 handleError(&SitesSP, err, "Selecting sites");
1168 return;
1169 }
1170
1171 if ( ( err = getSiteLatitude(fd, &dd, &mm) < 0))
1172 {
1173 handleError(&SitesSP, err, "Selecting sites");
1174 return;
1175 }
1176
1177 if (dd > 0) geoNP.np[0].value = dd + mm / 60.0;
1178 else geoNP.np[0].value = dd - mm / 60.0;
1179
1180 if ( ( err = getSiteLongitude(fd, &dd, &mm) < 0))
1181 {
1182 handleError(&SitesSP, err, "Selecting sites");
1183 return;
1184 }
1185
1186 if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm / 60.0);
1187 else geoNP.np[1].value = (dd - mm / 60.0) * -1.0;
1188
1189 getSiteName(fd, SiteNameTP.tp[0].text, currentSiteNum);
1190
1191 IDLog("Selecting site %d\n", currentSiteNum);
1192
1193 geoNP.s = SiteNameTP.s = SitesSP.s = IPS_OK;
1194
1195 IDSetNumber (&geoNP, NULL);
1196 IDSetText (&SiteNameTP, NULL);
1197 IDSetSwitch (&SitesSP, NULL);
1198 return;
1199 }
1200
1201 // Focus Motion
1202 if (!strcmp (name, FocusMotionSP.name))
1203 {
1204 if (checkPower(&FocusMotionSP))
1205 return;
1206
1207 // If mode is "halt"
1208 if (FocusModeS[0].s == ISS_ON)
1209 {
1210 FocusMotionSP.s = IPS_IDLE;
1211 IDSetSwitch(&FocusMotionSP, NULL);
1212 return;
1213 }
1214
1215 if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return;
1216 index = getOnSwitch(&FocusMotionSP);
1217
1218 if ( ( err = setFocuserMotion(fd, index) < 0) )
1219 {
1220 handleError(&FocusMotionSP, err, "Setting focuser speed");
1221 return;
1222 }
1223
1224 FocusMotionSP.s = IPS_BUSY;
1225
1226 // with a timer
1227 if (FocusTimerN[0].value > 0)
1228 {
1229 FocusTimerNP.s = IPS_BUSY;
1230 IEAddTimer(50, LX200Generic::updateFocusTimer, this);
1231 }
1232
1233 IDSetSwitch(&FocusMotionSP, NULL);
1234 return;
1235 }
1236
1237 // Slew mode
1238 if (!strcmp (name, SlewModeSP.name))
1239 {
1240 if (checkPower(&SlewModeSP))
1241 return;
1242
1243 if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return;
1244 index = getOnSwitch(&SlewModeSP);
1245
1246 if ( ( err = setSlewMode(fd, index) < 0) )
1247 {
1248 handleError(&SlewModeSP, err, "Setting slew mode");
1249 return;
1250 }
1251
1252 SlewModeSP.s = IPS_OK;
1253 IDSetSwitch(&SlewModeSP, NULL);
1254 return;
1255 }
1256
1257 // Movement (North/South)
1258 if (!strcmp (name, MovementNSSP.name))
1259 {
1260 if (checkPower(&MovementNSSP))
1261 return;
1262 if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
1263 {
1264 handleError(&MovementNSSP, err, "Can't move while guiding");
1265 return;
1266 }
1267
1268 int last_move=-1;
1269 int current_move = -1;
1270
1271 // -1 means all off previously
1272 last_move = getOnSwitch(&MovementNSSP);
1273
1274 if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0)
1275 return;
1276
1277 current_move = getOnSwitch(&MovementNSSP);
1278
1279 // Previosuly active switch clicked again, so let's stop.
1280 if (current_move == last_move)
1281 {
1282 HaltMovement(fd, (current_move == 0) ? LX200_NORTH : LX200_SOUTH);
1283 IUResetSwitch(&MovementNSSP);
1284 MovementNSSP.s = IPS_IDLE;
1285 IDSetSwitch(&MovementNSSP, NULL);
1286 return;
1287 }
1288
1289 #ifdef INDI_DEBUG
1290 IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
1291 #endif
1292
1293 // 0 (North) or 1 (South)
1294 last_move = current_move;
1295
1296 // Correction for LX200 Driver: North 0 - South 3
1297 current_move = (current_move == 0) ? LX200_NORTH : LX200_SOUTH;
1298
1299 if ( ( err = MoveTo(fd, current_move) < 0) )
1300 {
1301 handleError(&MovementNSSP, err, "Setting motion direction");
1302 return;
1303 }
1304
1305 MovementNSSP.s = IPS_BUSY;
1306 IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == LX200_NORTH) ? "North" : "South");
1307 return;
1308 }
1309
1310 // Movement (West/East)
1311 if (!strcmp (name, MovementWESP.name))
1312 {
1313 if (checkPower(&MovementWESP))
1314 return;
1315 if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
1316 {
1317 handleError(&MovementWESP, err, "Can't move while guiding");
1318 return;
1319 }
1320
1321 int last_move=-1;
1322 int current_move = -1;
1323
1324 // -1 means all off previously
1325 last_move = getOnSwitch(&MovementWESP);
1326
1327 if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0)
1328 return;
1329
1330 current_move = getOnSwitch(&MovementWESP);
1331
1332 // Previosuly active switch clicked again, so let's stop.
1333 if (current_move == last_move)
1334 {
1335 HaltMovement(fd, (current_move ==0) ? LX200_WEST : LX200_EAST);
1336 IUResetSwitch(&MovementWESP);
1337 MovementWESP.s = IPS_IDLE;
1338 IDSetSwitch(&MovementWESP, NULL);
1339 return;
1340 }
1341
1342 #ifdef INDI_DEBUG
1343 IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
1344 #endif
1345
1346 // 0 (West) or 1 (East)
1347 last_move = current_move;
1348
1349 // Correction for LX200 Driver: West 1 - East 2
1350 current_move = (current_move == 0) ? LX200_WEST : LX200_EAST;
1351
1352 if ( ( err = MoveTo(fd, current_move) < 0) )
1353 {
1354 handleError(&MovementWESP, err, "Setting motion direction");
1355 return;
1356 }
1357
1358 MovementWESP.s = IPS_BUSY;
1359 IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == LX200_WEST) ? "West" : "East");
1360 return;
1361 }
1362
1363 // Tracking mode
1364 if (!strcmp (name, TrackModeSP.name))
1365 {
1366 if (checkPower(&TrackModeSP))
1367 return;
1368
1369 IUResetSwitch(&TrackModeSP);
1370 IUUpdateSwitch(&TrackModeSP, states, names, n);
1371 trackingMode = getOnSwitch(&TrackModeSP);
1372
1373 if ( ( err = selectTrackingMode(fd, trackingMode) < 0) )
1374 {
1375 handleError(&TrackModeSP, err, "Setting tracking mode.");
1376 return;
1377 }
1378
1379 getTrackFreq(fd, &TrackFreqN[0].value);
1380 TrackModeSP.s = IPS_OK;
1381 IDSetNumber(&TrackingFreqNP, NULL);
1382 IDSetSwitch(&TrackModeSP, NULL);
1383 return;
1384 }
1385
1386 // Focus speed
1387 if (!strcmp (name, FocusModeSP.name))
1388 {
1389 if (checkPower(&FocusModeSP))
1390 return;
1391
1392 IUResetSwitch(&FocusModeSP);
1393 IUUpdateSwitch(&FocusModeSP, states, names, n);
1394
1395 index = getOnSwitch(&FocusModeSP);
1396
1397 /* disable timer and motion */
1398 if (index == 0)
1399 {
1400 IUResetSwitch(&FocusMotionSP);
1401 FocusMotionSP.s = IPS_IDLE;
1402 FocusTimerNP.s = IPS_IDLE;
1403 IDSetSwitch(&FocusMotionSP, NULL);
1404 IDSetNumber(&FocusTimerNP, NULL);
1405 }
1406
1407 setFocuserSpeedMode(fd, index);
1408 FocusModeSP.s = IPS_OK;
1409 IDSetSwitch(&FocusModeSP, NULL);
1410 return;
1411 }
1412
1413 // Pulse-Guide command support
1414 if (!strcmp (name, UsePulseCmdSP.name))
1415 {
1416 if (checkPower(&UsePulseCmdSP))
1417 return;
1418
1419 IUResetSwitch(&UsePulseCmdSP);
1420 IUUpdateSwitch(&UsePulseCmdSP, states, names, n);
1421
1422 UsePulseCmdSP.s = IPS_OK;
1423 IDSetSwitch(&UsePulseCmdSP, NULL);
1424 return;
1425 }
1426}
1427
1428void LX200Generic::handleError(ISwitchVectorProperty *svp, int err, const char *msg)
1429{
1430
1431 svp->s = IPS_ALERT;
1432
1433 /* First check to see if the telescope is connected */
1434 if (check_lx200_connection(fd))
1435 {
1436 /* The telescope is off locally */
1437 ConnectS[0].s = ISS_OFF;
1438 ConnectS[1].s = ISS_ON;
1439 ConnectSP.s = IPS_BUSY;
1440 IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1441
1442 IDSetSwitch(svp, NULL);
1443 IEAddTimer(10000, retryConnection, &fd);
1444 return;
1445 }
1446
1447 /* If the error is a time out, then the device doesn't support this property or busy*/
1448 if (err == -2)
1449 {
1450 svp->s = IPS_ALERT;
1451 IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1452 }
1453 else
1454 /* Changing property failed, user should retry. */
1455 IDSetSwitch( svp , "%s failed.", msg);
1456
1457 fault = true;
1458}
1459
1460void LX200Generic::handleError(INumberVectorProperty *nvp, int err, const char *msg)
1461{
1462
1463 nvp->s = IPS_ALERT;
1464
1465 /* First check to see if the telescope is connected */
1466 if (check_lx200_connection(fd))
1467 {
1468 /* The telescope is off locally */
1469 ConnectS[0].s = ISS_OFF;
1470 ConnectS[1].s = ISS_ON;
1471 ConnectSP.s = IPS_BUSY;
1472 IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1473
1474 IDSetNumber(nvp, NULL);
1475 IEAddTimer(10000, retryConnection, &fd);
1476 return;
1477 }
1478
1479 /* If the error is a time out, then the device doesn't support this property */
1480 if (err == -2)
1481 {
1482 nvp->s = IPS_ALERT;
1483 IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1484 }
1485 else
1486 /* Changing property failed, user should retry. */
1487 IDSetNumber( nvp , "%s failed.", msg);
1488
1489 fault = true;
1490}
1491
1492void LX200Generic::handleError(ITextVectorProperty *tvp, int err, const char *msg)
1493{
1494
1495 tvp->s = IPS_ALERT;
1496
1497 /* First check to see if the telescope is connected */
1498 if (check_lx200_connection(fd))
1499 {
1500 /* The telescope is off locally */
1501 ConnectS[0].s = ISS_OFF;
1502 ConnectS[1].s = ISS_ON;
1503 ConnectSP.s = IPS_BUSY;
1504 IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
1505
1506 IDSetText(tvp, NULL);
1507 IEAddTimer(10000, retryConnection, &fd);
1508 return;
1509 }
1510
1511 /* If the error is a time out, then the device doesn't support this property */
1512 if (err == -2)
1513 {
1514 tvp->s = IPS_ALERT;
1515 IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
1516 }
1517
1518 else
1519 /* Changing property failed, user should retry. */
1520 IDSetText( tvp , "%s failed.", msg);
1521
1522 fault = true;
1523}
1524
1525 void LX200Generic::correctFault()
1526 {
1527
1528 fault = false;
1529 IDMessage(thisDevice, "Telescope is online.");
1530
1531 }
1532
1533bool LX200Generic::isTelescopeOn(void)
1534{
1535 //if (simulation) return true;
1536
1537 return (ConnectSP.sp[0].s == ISS_ON);
1538}
1539
1540static void retryConnection(void * p)
1541{
1542 int fd = *( (int *) p);
1543
1544 if (check_lx200_connection(fd))
1545 {
1546 ConnectSP.s = IPS_IDLE;
1547 IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
1548 return;
1549 }
1550
1551 ConnectS[0].s = ISS_ON;
1552 ConnectS[1].s = ISS_OFF;
1553 ConnectSP.s = IPS_OK;
1554
1555 IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
1556
1557}
1558
1559void LX200Generic::updateFocusTimer(void *p)
1560{
1561 int err=0;
1562
1563 switch (FocusTimerNP.s)
1564 {
1565
1566 case IPS_IDLE:
1567 break;
1568
1569 case IPS_BUSY:
1570 IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value);
1571 FocusTimerN[0].value-=50;
1572
1573 if (FocusTimerN[0].value <= 0)
1574 {
1575 IDLog("Focus Timer Expired\n");
1576 if ( ( err = setFocuserSpeedMode(telescope->fd, 0) < 0) )
1577 {
1578 telescope->handleError(&FocusModeSP, err, "setting focuser mode");
1579 IDLog("Error setting focuser mode\n");
1580 return;
1581 }
1582
1583
1584 FocusMotionSP.s = IPS_IDLE;
1585 FocusTimerNP.s = IPS_OK;
1586 FocusModeSP.s = IPS_OK;
1587
1588 IUResetSwitch(&FocusMotionSP);
1589 IUResetSwitch(&FocusModeSP);
1590 FocusModeS[0].s = ISS_ON;
1591
1592 IDSetSwitch(&FocusModeSP, NULL);
1593 IDSetSwitch(&FocusMotionSP, NULL);
1594 }
1595
1596 IDSetNumber(&FocusTimerNP, NULL);
1597
1598 if (FocusTimerN[0].value > 0)
1599 IEAddTimer(50, LX200Generic::updateFocusTimer, p);
1600 break;
1601
1602 case IPS_OK:
1603 break;
1604
1605 case IPS_ALERT:
1606 break;
1607 }
1608
1609}
1610
1611void LX200Generic::guideTimeout(void *p)
1612{
1613 long direction = (long)p;
1614 int use_pulse_cmd;
1615
1616 use_pulse_cmd = telescope->getOnSwitch(&UsePulseCmdSP);
1617 if (direction == -1)
1618 {
1619 HaltMovement(telescope->fd, LX200_NORTH);
1620 HaltMovement(telescope->fd, LX200_SOUTH);
1621 HaltMovement(telescope->fd, LX200_EAST);
1622 HaltMovement(telescope->fd, LX200_WEST);
1623 IERmTimer(telescope->GuideNSTID);
1624 IERmTimer(telescope->GuideWETID);
1625
1626 }
1627 else if (! use_pulse_cmd)
1628 {
1629 HaltMovement(telescope->fd, direction);
1630 }
1631 if (direction == LX200_NORTH || direction == LX200_SOUTH || direction == -1)
1632 {
1633 GuideNSNP.np[0].value = 0;
1634 GuideNSNP.np[1].value = 0;
1635 GuideNSNP.s = IPS_IDLE;
1636 telescope->GuideNSTID = 0;
1637 IDSetNumber(&GuideNSNP, NULL);
1638 }
1639 if (direction == LX200_WEST || direction == LX200_EAST || direction == -1)
1640 {
1641 GuideWENP.np[0].value = 0;
1642 GuideWENP.np[1].value = 0;
1643 GuideWENP.s = IPS_IDLE;
1644 telescope->GuideWETID = 0;
1645 IDSetNumber(&GuideWENP, NULL);
1646 }
1647}
1648
1649void LX200Generic::ISPoll()
1650{
1651 double dx, dy;
1652 /*static int okCounter = 3;*/
1653 int err=0;
1654
1655 if (!isTelescopeOn())
1656 return;
1657
1658 if (simulation)
1659 {
1660 mountSim();
1661 return;
1662 }
1663
1664 if ( (err = getLX200RA(fd, &currentRA)) < 0 || (err = getLX200DEC(fd, &currentDEC)) < 0)
1665 {
1666 EquatorialCoordsRNP.s = IPS_ALERT;
1667 IDSetNumber(&EquatorialCoordsRNP, NULL);
1668 handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
1669 return;
1670 }
1671
1672 if (fault)
1673 correctFault();
1674
1675 EquatorialCoordsRNP.s = IPS_OK;
1676
1677 if ( fabs(lastRA - currentRA) > (SlewAccuracyN[0].value/(60.0*15.0)) || fabs(lastDEC - currentDEC) > (SlewAccuracyN[1].value/60.0))
1678 {
1679 lastRA = currentRA;
1680 lastDEC = currentDEC;
1681 IDSetNumber (&EquatorialCoordsRNP, NULL);
1682 }
1683
1684 switch (EquatorialCoordsWNP.s)
1685 {
1686 case IPS_IDLE:
1687 break;
1688
1689 case IPS_BUSY:
1690 dx = targetRA - currentRA;
1691 dy = targetDEC - currentDEC;
1692
1693 // Wait until acknowledged or within threshold
1694 if ( fabs(dx) <= (SlewAccuracyN[0].value/(60.0*15.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0))
1695 {
1696 lastRA = currentRA;
1697 lastDEC = currentDEC;
1698
1699 EquatorialCoordsWNP.s = IPS_OK;
1700 IDSetNumber(&EquatorialCoordsWNP, "Slew is complete, target locked...");
1701
1702 break;
1703
1704 case IPS_OK:
1705 break;
1706
1707
1708 case IPS_ALERT:
1709 break;
1710 }
1711}
1712
1713}
1714// wildi nothing changed in LX200Generic::mountSim
1715void LX200Generic::mountSim ()
1716{
1717 static struct timeval ltv;
1718 struct timeval tv;
1719 double dt, da, dx;
1720 int nlocked;
1721
1722 /* update elapsed time since last poll, don't presume exactly POLLMS */
1723 gettimeofday (&tv, NULL);
1724
1725 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1726 ltv = tv;
1727
1728 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6;
1729 ltv = tv;
1730 da = SLEWRATE*dt;
1731
1732 /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
1733 switch (EquatorialCoordsWNP.s)
1734 {
1735
1736 /* #1 State is idle, update telesocpe at sidereal rate */
1737 case IPS_IDLE:
1738 /* RA moves at sidereal, Dec stands still */
1739 currentRA += (SIDRATE*dt/15.);
1740
1741 IDSetNumber(&EquatorialCoordsRNP, NULL);
1742
1743 break;
1744
1745 case IPS_BUSY:
1746 /* slewing - nail it when both within one pulse @ SLEWRATE */
1747 nlocked = 0;
1748
1749 dx = targetRA - currentRA;
1750
1751 if (fabs(dx) <= da)
1752 {
1753 currentRA = targetRA;
1754 nlocked++;
1755 }
1756 else if (dx > 0)
1757 currentRA += da/15.;
1758 else
1759 currentRA -= da/15.;
1760
1761
1762 dx = targetDEC - currentDEC;
1763 if (fabs(dx) <= da)
1764 {
1765 currentDEC = targetDEC;
1766 nlocked++;
1767 }
1768 else if (dx > 0)
1769 currentDEC += da;
1770 else
1771 currentDEC -= da;
1772
1773 if (nlocked == 2)
1774 {
1775 EquatorialCoordsRNP.s = IPS_OK;
1776 EquatorialCoordsWNP.s = IPS_OK;
1777 IDSetNumber(&EquatorialCoordsWNP, "Now tracking");
1778 IDSetNumber(&EquatorialCoordsRNP, NULL);
1779 } else
1780 IDSetNumber(&EquatorialCoordsRNP, NULL);
1781
1782 break;
1783
1784 case IPS_OK:
1785 /* tracking */
1786 IDSetNumber(&EquatorialCoordsRNP, NULL);
1787 break;
1788
1789 case IPS_ALERT:
1790 break;
1791 }
1792
1793}
1794
1795void LX200Generic::getBasicData()
1796{
1797
1798 int err;
1799 #ifdef HAVE_NOVA_H
1800 struct tm *timep;
1801 time_t ut;
1802 time (&ut);
1803 timep = gmtime (&ut);
1804 strftime (TimeTP.tp[0].text, strlen(TimeTP.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep);
1805
1806 IDLog("PC UTC time is %s\n", TimeTP.tp[0].text);
1807 #endif
1808
1809 getAlignment();
1810
1811 checkLX200Format(fd);
1812
1813 if ( (err = getTimeFormat(fd, &timeFormat)) < 0)
1814 IDMessage(thisDevice, "Failed to retrieve time format from device.");
1815 else
1816 {
1817 timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM;
1818 // We always do 24 hours
1819 if (timeFormat != LX200_24)
1820 err = toggleTimeFormat(fd);
1821 }
1822// wildi proposal
1823 if ( (err = getLX200RA(fd, &targetRA)) < 0 || (err = getLX200DEC(fd, &targetDEC)) < 0)
1824 {
1825 EquatorialCoordsRNP.s = IPS_ALERT;
1826 IDSetNumber(&EquatorialCoordsRNP, NULL);
1827 handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
1828 return;
1829 }
1830
1831 if (fault)
1832 correctFault();
1833
1834// getLX200RA(fd, &targetRA);
1835// getLX200DEC(fd, &targetDEC);
1836
1837 EquatorialCoordsRNP.np[0].value = targetRA;
1838 EquatorialCoordsRNP.np[1].value = targetDEC;
1839
1840 EquatorialCoordsRNP.s = IPS_OK;
1841 IDSetNumber (&EquatorialCoordsRNP, NULL);
1842
1843 SiteNameT[0].text = new char[64];
1844
1845 if ( (err = getSiteName(fd, SiteNameT[0].text, currentSiteNum)) < 0)
1846 IDMessage(thisDevice, "Failed to get site name from device");
1847 else
1848 IDSetText (&SiteNameTP, NULL);
1849
1850 if ( (err = getTrackFreq(fd, &TrackFreqN[0].value)) < 0)
1851 IDMessage(thisDevice, "Failed to get tracking frequency from device.");
1852 else
1853 IDSetNumber (&TrackingFreqNP, NULL);
1854
1855 /*updateLocation();
1856 updateTime();*/
1857
1858}
1859
1860int LX200Generic::handleCoordSet()
1861{
1862
1863 int err;
1864 char syncString[256];
1865 char RAStr[32], DecStr[32];
1866
1867 switch (currentSet)
1868 {
1869 // Slew
1870 case LX200_TRACK:
1871 lastSet = LX200_TRACK;
1872 if (EquatorialCoordsWNP.s == IPS_BUSY)
1873 {
1874 #ifdef INDI_DEBUG
1875 IDLog("Aboring Slew\n");
1876 #endif
1877 if (abortSlew(fd) < 0)
1878 {
1879 AbortSlewSP.s = IPS_ALERT;
1880 IDSetSwitch(&AbortSlewSP, NULL);
1881 slewError(err);
1882 return (-1);
1883 }
1884
1885 AbortSlewSP.s = IPS_OK;
1886 EquatorialCoordsWNP.s = IPS_IDLE;
1887 IDSetSwitch(&AbortSlewSP, "Slew aborted.");
1888 IDSetNumber(&EquatorialCoordsWNP, NULL);
1889
1890 if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
1891 {
1892 MovementNSSP.s = MovementWESP.s = IPS_IDLE;
1893 EquatorialCoordsWNP.s = IPS_IDLE;
1894 IUResetSwitch(&MovementNSSP);
1895 IUResetSwitch(&MovementWESP);
1896 IUResetSwitch(&AbortSlewSP);
1897
1898 IDSetSwitch(&MovementNSSP, NULL);
1899 IDSetSwitch(&MovementWESP, NULL);
1900 }
1901
1902 // sleep for 100 mseconds
1903 usleep(100000);
1904 }
1905
1906 if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
1907 {
1908 IDMessage(mydev "ERROR Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
1909 slewError(err);
1910 return -1;
1911 }
1912
1913 EquatorialCoordsWNP.s = IPS_BUSY;
1914 fs_sexa(RAStr, targetRA, 2, 3600);
1915 fs_sexa(DecStr, targetDEC, 2, 3600);
1916 IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
1917 #ifdef INDI_DEBUG
1918 IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
1919 #endif
1920 break;
1921
1922 // Sync
1923 case LX200_SYNC:
1924 lastSet = LX200_SYNC;
1925
1926 if (!simulation)
1927 if ( ( err = Sync(fd, syncString) < 0) )
1928 {
1929 EquatorialCoordsWNP.s = IPS_ALERT;
1930 IDSetNumber(&EquatorialCoordsWNP , "Synchronization failed.");
1931 return (-1);
1932 }
1933
1934 EquatorialCoordsWNP.s = IPS_OK;
1935 IDLog("Synchronization successful %s\n", syncString);
1936 IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
1937 break;
1938
1939 }
1940
1941 return (0);
1942
1943}
1944
1945int LX200Generic::getOnSwitch(ISwitchVectorProperty *sp)
1946{
1947 for (int i=0; i < sp->nsp ; i++)
1948 if (sp->sp[i].s == ISS_ON)
1949 return i;
1950
1951 return -1;
1952}
1953
1954
1955int LX200Generic::checkPower(ISwitchVectorProperty *sp)
1956{
1957 if (simulation) return 0;
1958
1959 if (ConnectSP.s != IPS_OK)
1960 {
1961 if (!strcmp(sp->label, ""))
1962 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name);
1963 else
1964 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label);
1965
1966 sp->s = IPS_IDLE;
1967 IDSetSwitch(sp, NULL);
1968 return -1;
1969 }
1970
1971 return 0;
1972}
1973
1974int LX200Generic::checkPower(INumberVectorProperty *np)
1975{
1976 if (simulation) return 0;
1977
1978 if (ConnectSP.s != IPS_OK)
1979 {
1980 if (!strcmp(np->label, ""))
1981 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name);
1982 else
1983 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label);
1984
1985 np->s = IPS_IDLE;
1986 IDSetNumber(np, NULL);
1987 return -1;
1988 }
1989
1990 return 0;
1991
1992}
1993
1994int LX200Generic::checkPower(ITextVectorProperty *tp)
1995{
1996
1997 if (simulation) return 0;
1998
1999 if (ConnectSP.s != IPS_OK)
2000 {
2001 if (!strcmp(tp->label, ""))
2002 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name);
2003 else
2004 IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label);
2005
2006 tp->s = IPS_IDLE;
2007 IDSetText(tp, NULL);
2008 return -1;
2009 }
2010
2011 return 0;
2012
2013}
2014
2015void LX200Generic::connectTelescope()
2016{
2017 switch (ConnectSP.sp[0].s)
2018 {
2019 case ISS_ON:
2020
2021 if (simulation)
2022 {
2023 ConnectSP.s = IPS_OK;
2024 IDSetSwitch (&ConnectSP, "Simulated telescope is online.");
2025 //updateTime();
2026 return;
2027 }
2028
2029 if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
2030 {
2031 ConnectS[0].s = ISS_OFF;
2032 ConnectS[1].s = ISS_ON;
2033 IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text);
2034 return;
2035 }
2036 if (check_lx200_connection(fd))
2037 {
2038 ConnectS[0].s = ISS_OFF;
2039 ConnectS[1].s = ISS_ON;
2040 IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
2041 return;
2042 }
2043
2044 #ifdef INDI_DEBUG
2045 IDLog("Telescope test successfful.\n");
2046 #endif
2047
2048 *((int *) UTCOffsetN[0].aux0) = 0;
2049 ConnectSP.s = IPS_OK;
2050 IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
2051 getBasicData();
2052 break;
2053
2054 case ISS_OFF:
2055 ConnectS[0].s = ISS_OFF;
2056 ConnectS[1].s = ISS_ON;
2057 ConnectSP.s = IPS_IDLE;
2058 IDSetSwitch (&ConnectSP, "Telescope is offline.");
2059 IDLog("Telescope is offline.");
2060 tty_disconnect(fd);
2061 break;
2062
2063 }
2064
2065}
2066
2067void LX200Generic::slewError(int slewCode)
2068{
2069 EquatorialCoordsWNP.s = IPS_ALERT;
2070
2071 if (slewCode == 1)
2072 IDSetNumber(&EquatorialCoordsWNP, "Object below horizon.");
2073 else if (slewCode == 2)
2074 IDSetNumber(&EquatorialCoordsWNP, "Object below the minimum elevation limit.");
2075 else
2076 IDSetNumber(&EquatorialCoordsWNP, "Slew failed.");
2077
2078}
2079
2080void LX200Generic::getAlignment()
2081{
2082
2083 if (ConnectSP.s != IPS_OK)
2084 return;
2085
2086 signed char align = ACK(fd);
2087 if (align < 0)
2088 {
2089 IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment.");
2090 return;
2091 }
2092
2093 AlignmentS[0].s = ISS_OFF;
2094 AlignmentS[1].s = ISS_OFF;
2095 AlignmentS[2].s = ISS_OFF;
2096
2097 switch (align)
2098 {
2099 case 'P': AlignmentS[0].s = ISS_ON;
2100 break;
2101 case 'A': AlignmentS[1].s = ISS_ON;
2102 break;
2103 case 'L': AlignmentS[2].s = ISS_ON;
2104 break;
2105 }
2106
2107 AlignmentSw.s = IPS_OK;
2108 IDSetSwitch (&AlignmentSw, NULL);
2109 IDLog("ACK success %c\n", align);
2110}
2111
2112void LX200Generic::enableSimulation(bool enable)
2113{
2114 simulation = enable;
2115
2116 if (simulation)
2117 IDLog("Warning: Simulation is activated.\n");
2118 else
2119 IDLog("Simulation is disabled.\n");
2120}
2121
2122void LX200Generic::updateTime()
2123{
2124 #ifdef HAVE_NOVA_H
2125 char cdate[32];
2126 double ctime;
2127 int h, m, s, lx200_utc_offset=0;
2128 int day, month, year, result;
2129 struct tm ltm;
2130 struct tm utm;
2131 time_t time_epoch;
2132
2133 if (simulation)
2134 {
2135 sprintf(TimeT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
2136 IDLog("Telescope ISO date and time: %s\n", TimeT[0].text);
2137 IDSetText(&TimeTP, NULL);
2138 return;
2139 }
2140
2141 getUTCOffset(fd, &lx200_utc_offset);
2142
2143 // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
2144 UTCOffsetN[0].value = lx200_utc_offset*-1;
2145
2146 // We got a valid value for UTCOffset now
2147 *((int *) UTCOffsetN[0].aux0) = 1;
2148
2149 #ifdef INDI_DEBUG
2150 IDLog("Telescope TimeT Offset: %g\n", UTCOffsetN[0].value);
2151 #endif
2152
2153 getLocalTime24(fd, &ctime);
2154 getSexComponents(ctime, &h, &m, &s);
2155
2156 if ( (result = getSDTime(fd, &SDTimeN[0].value)) < 0)
2157 IDMessage(thisDevice, "Failed to retrieve siderial time from device.");
2158
2159 getCalenderDate(fd, cdate);
2160 result = sscanf(cdate, "%d/%d/%d", &year, &month, &day);
2161 if (result != 3) return;
2162
2163 // Let's fill in the local time
2164 ltm.tm_sec = s;
2165 ltm.tm_min = m;
2166 ltm.tm_hour = h;
2167 ltm.tm_mday = day;
2168 ltm.tm_mon = month - 1;
2169 ltm.tm_year = year - 1900;
2170
2171 // Get time epoch
2172 time_epoch = mktime(&ltm);
2173
2174 // Convert to TimeT
2175 time_epoch -= (int) (UTCOffsetN[0].value * 60.0 * 60.0);
2176
2177 // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time)
2178 localtime_r(&time_epoch, &utm);
2179
2180 /* Format it into ISO 8601 */
2181 strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm);
2182 IUSaveText(&TimeT[0], cdate);
2183
2184 #ifdef INDI_DEBUG
2185 IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s);
2186 IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value);
2187 IDLog("Telescope UTC Time: %s\n", TimeT[0].text);
2188 #endif
2189
2190 // Let's send everything to the client
2191 IDSetText(&TimeTP, NULL);
2192 IDSetNumber(&SDTimeNP, NULL);
2193 IDSetNumber(&UTCOffsetNP, NULL);
2194 #endif
2195
2196}
2197
2198void LX200Generic::updateLocation()
2199{
2200
2201 int dd = 0, mm = 0, err = 0;
2202
2203 if (simulation)
2204 return;
2205
2206 if ( (err = getSiteLatitude(fd, &dd, &mm)) < 0)
2207 IDMessage(thisDevice, "Failed to get site latitude from device.");
2208 else
2209 {
2210 if (dd > 0)
2211 geoNP.np[0].value = dd + mm/60.0;
2212 else
2213 geoNP.np[0].value = dd - mm/60.0;
2214
2215 IDLog("Autostar Latitude: %d:%d\n", dd, mm);
2216 IDLog("INDI Latitude: %g\n", geoNP.np[0].value);
2217 }
2218
2219 if ( (err = getSiteLongitude(fd, &dd, &mm)) < 0)
2220 IDMessage(thisDevice, "Failed to get site longitude from device.");
2221 else
2222 {
2223 if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm/60.0);
2224 else geoNP.np[1].value = (dd - mm/60.0) * -1.0;
2225
2226 IDLog("Autostar Longitude: %d:%d\n", dd, mm);
2227 IDLog("INDI Longitude: %g\n", geoNP.np[1].value);
2228 }
2229
2230 IDSetNumber (&geoNP, NULL);
2231
2232}
2233
Note: See TracBrowser for help on using the repository browser.