~ubuntu-branches/ubuntu/quantal/libindi/quantal

« back to all changes in this revision

Viewing changes to drivers/telescope/lx200generic.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2009-02-13 20:26:22 UTC
  • Revision ID: james.westby@ubuntu.com-20090213202622-hz9rulzxa2akq5vw
Tags: upstream-0.6
ImportĀ upstreamĀ versionĀ 0.6

Show diffs side-by-side

added added

removed removed

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