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

Last change on this file since 654 was 501, checked in by frichard, 15 years ago

-BAOControl : petite interface permettant de contrôler les antennes via le pilote indi_BAO
-Le pilote indi_BAO utilise désormais libindi v 0.7

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