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

Last change on this file since 614 was 501, checked in by frichard, 14 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.= 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.= 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.= 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.= 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.= 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.= 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.