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

« back to all changes in this revision

Viewing changes to drivers/telescope/lx200ap.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
/*
 
2
    LX200 Astro-Physics INDI driver, tested with controller software version D
 
3
    Copyright (C) 2007 Markus Wildi based on the work of Jasem Mutlaq 
 
4
    (mutlaqja@ikarustech.com)
 
5
 
 
6
    This library is free software; you can redistribute it and/or
 
7
    modify it under the terms of the GNU Lesser General Public
 
8
    License as published by the Free Software Foundation; either
 
9
    version 2.1 of the License, or (at your option) any later version.
 
10
 
 
11
    This library is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
    Lesser General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU Lesser General Public
 
17
    License along with this library; if not, write to the Free Software
 
18
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 
 
20
*/
 
21
 
 
22
 
 
23
//HAVE_NOVASCC_H: NOVAS-C, Version 2.0.1, Astronomical Applications Dept. 
 
24
//U.S. Naval Observatory, Washington, DC  20392-5420 http://aa.usno.navy.mil/AA/
 
25
//#define HAVE_NOVASCC_H
 
26
//HAVE_NOVA_H: http://libnova.sourceforge.net/
 
27
//#define HAVE_NOVA_H
 
28
 
 
29
#include "lx200ap.h"
 
30
#include "lx200driver.h"
 
31
#include "lx200apdriver.h"
 
32
#include "lx200aplib.h"
 
33
 
 
34
#include <config.h>
 
35
 
 
36
#ifdef HAVE_NOVA_H
 
37
#include <libnova.h>
 
38
#endif
 
39
 
 
40
#include <stdio.h>
 
41
#include <stdlib.h>
 
42
#include <string.h>
 
43
#include <unistd.h>
 
44
 
 
45
#define COMM_GROUP       "Communication"
 
46
#define BASIC_GROUP      "Main Control"
 
47
#define MOTION_GROUP     "Motion Control"
 
48
#define FIRMWARE_GROUP   "Firmware data"
 
49
#define SETTINGS_GROUP   "Settings"
 
50
#define ATMOSPHERE_GROUP "Atmosphere"
 
51
#define MOUNT_GROUP      "Mounting"
 
52
 
 
53
/* Handy Macros */
 
54
#define currentRA       EquatorialCoordsRNP.np[0].value
 
55
#define currentDEC      EquatorialCoordsRNP.np[1].value
 
56
#define targetRA        EquatorialCoordsWNP.np[0].value
 
57
#define targetDEC       EquatorialCoordsWNP.np[1].value
 
58
#define currentAZ       HorizontalCoordsRNP.np[0].value
 
59
#define currentALT      HorizontalCoordsRNP.np[1].value
 
60
#define targetAZ        HorizontalCoordsWNP.np[0].value
 
61
#define targetALT       HorizontalCoordsWNP.np[1].value
 
62
 
 
63
/* SNOOP */
 
64
 
 
65
#define CONTROL_GROUP    "Control"
 
66
 
 
67
/* Do not forget to remove static in lx200generic.cpp */
 
68
extern INumberVectorProperty EquatorialCoordsWNP;
 
69
extern INumberVectorProperty EquatorialCoordsRNP;
 
70
extern ITextVectorProperty   PortTP ;
 
71
extern ISwitchVectorProperty MovementNSSP ;
 
72
extern ISwitchVectorProperty MovementWESP ;
 
73
extern ISwitchVectorProperty ConnectSP ;
 
74
extern ISwitchVectorProperty AbortSlewSP ;
 
75
extern ISwitchVectorProperty OnCoordSetSP ;
 
76
extern INumberVectorProperty geoNP ;
 
77
extern INumberVectorProperty TrackingAccuracyNP ;
 
78
extern INumberVectorProperty SlewAccuracyNP ;
 
79
 
 
80
/* Communication */
 
81
 
 
82
static ISwitch DomeControlS[] = 
 
83
{
 
84
    {"ON" , "on" , ISS_ON, 0, 0},
 
85
    {"OFF" , "off" , ISS_OFF, 0, 0},
 
86
};
 
87
 
 
88
ISwitchVectorProperty DomeControlSP = 
 
89
 
90
    myapdev, "DOMECONTROL" , "Dome control", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeControlS, NARRAY(DomeControlS), "", 0
 
91
};
 
92
 
 
93
static ISwitch StartUpS[] = 
 
94
{
 
95
    {"COLD" , "cold" , ISS_OFF, 0, 0},
 
96
    {"WARM" , "warm" , ISS_ON, 0, 0},
 
97
};
 
98
 
 
99
ISwitchVectorProperty StartUpSP = 
 
100
 
101
    myapdev, "STARTUP" , "Mount init.", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, StartUpS, NARRAY(StartUpS), "", 0
 
102
};
 
103
 
 
104
/* Main control */
 
105
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
106
static ISwitch ApparentToObservedS[] = 
 
107
{
 
108
    {"NCTC" , "identity" , ISS_ON, 0, 0},
 
109
    {"NATR" , "app. to refracted" , ISS_OFF, 0, 0},
 
110
    {"NARTT" , "app., refr., telescope" , ISS_OFF, 0, 0},
 
111
    {"NARTTO" , "app., refr., tel., observed" , ISS_OFF, 0, 0},
 
112
};
 
113
 
 
114
ISwitchVectorProperty ApparentToObservedSP = 
 
115
 
116
    myapdev, "TRANSFORMATION" , "Transformation", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ApparentToObservedS, NARRAY(ApparentToObservedS), "", 0
 
117
};
 
118
#endif
 
119
 
 
120
static INumber HourangleCoordsN[] = 
 
121
{
 
122
    {"HA",  "HA H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
 
123
    {"Dec",  "Dec D:M:S", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
 
124
};
 
125
static INumberVectorProperty  HourangleCoordsNP = 
 
126
{
 
127
    myapdev, "HOURANGLE_COORD", "Hourangle Coords", BASIC_GROUP, IP_RO, 0., IPS_IDLE, HourangleCoordsN, NARRAY( HourangleCoordsN), "", 0
 
128
};
 
129
static INumber HorizontalCoordsRN[] = 
 
130
{
 
131
    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
 
132
    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0}
 
133
};
 
134
static INumberVectorProperty HorizontalCoordsRNP = 
 
135
{
 
136
    myapdev, "HORIZONTAL_COORD", "Horizontal Coords", BASIC_GROUP, IP_RO, 120, IPS_IDLE, HorizontalCoordsRN, NARRAY(HorizontalCoordsRN), "", 0
 
137
};
 
138
 
 
139
/* Horizontal Coordinates: Request Only */
 
140
static INumber HorizontalCoordsWN[] = 
 
141
{
 
142
    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
 
143
    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0}
 
144
};
 
145
static INumberVectorProperty HorizontalCoordsWNP = 
 
146
{
 
147
    myapdev, "HORIZONTAL_COORD_REQUEST", "Horizontal Coords", BASIC_GROUP, IP_WO, 120, IPS_IDLE, HorizontalCoordsWN, NARRAY(HorizontalCoordsWN), "", 0
 
148
};
 
149
/* Difference of the equatorial coordinates, used to estimate the applied corrections */
 
150
static INumber DiffEquatorialCoordsN[] = 
 
151
{
 
152
    {"RA",  "RA H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
 
153
    {"Dec",  "Dec D:M:S", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
 
154
};
 
155
static INumberVectorProperty  DiffEquatorialCoordsNP = 
 
156
{
 
157
    myapdev, "DIFFEQUATORIAL_COORD", "Diff. Eq.", BASIC_GROUP, IP_RO, 0., IPS_IDLE, DiffEquatorialCoordsN, NARRAY( DiffEquatorialCoordsN), "", 0
 
158
};
 
159
 
 
160
static ISwitch TrackModeS[] = {
 
161
    {"LUNAR" , "lunar" , ISS_OFF, 0, 0},
 
162
    {"SOLAR" , "solar" , ISS_OFF, 0, 0},
 
163
    {"SIDEREAL", "sidereal" , ISS_OFF, 0, 0},
 
164
    {"ZERO" , "zero" , ISS_ON, 0, 0},
 
165
};
 
166
ISwitchVectorProperty TrackModeSP = 
 
167
 
168
    myapdev, "TRACKINGMODE" , "Tracking mode", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0
 
169
};
 
170
static ISwitch MoveToRateS[] = {
 
171
    {"1200" , "1200x" , ISS_OFF, 0, 0},
 
172
    {"600" , "600x" , ISS_OFF, 0, 0},
 
173
    {"64" , "64x" , ISS_ON, 0, 0},
 
174
    {"12" , "12x" , ISS_OFF, 0, 0},
 
175
};
 
176
 
 
177
ISwitchVectorProperty MoveToRateSP = 
 
178
 
179
    myapdev, "MOVETORATE" , "Move to rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MoveToRateS, NARRAY(MoveToRateS), "", 0
 
180
};
 
181
static ISwitch SlewRateS[] = {
 
182
    {"1200" , "1200x" , ISS_OFF, 0, 0},
 
183
    {"900" , "900x" , ISS_OFF, 0, 0},
 
184
    {"600" , "600x" , ISS_ON, 0, 0},
 
185
};
 
186
 
 
187
ISwitchVectorProperty SlewRateSP = 
 
188
 
189
    myapdev, "SLEWRATE" , "Slew rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewRateS, NARRAY(SlewRateS), "", 0
 
190
};
 
191
static ISwitch SwapS[] = {
 
192
    {"NS" , "North/Sounth" , ISS_OFF, 0, 0},
 
193
    {"EW" , "East/West" , ISS_OFF, 0, 0},
 
194
};
 
195
 
 
196
ISwitchVectorProperty SwapSP = 
 
197
 
198
    myapdev, "SWAP" , "Swap buttons", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SwapS, NARRAY(SwapS), "", 0
 
199
};
 
200
static ISwitch SyncCMRS[] = {
 
201
    {":CM#" , ":CM#" , ISS_ON, 0, 0},
 
202
    {":CMR#" , ":CMR#" , ISS_OFF, 0, 0},
 
203
};
 
204
 
 
205
ISwitchVectorProperty SyncCMRSP = 
 
206
 
207
    myapdev, "SYNCCMR" , "Sync", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SyncCMRS, NARRAY(SyncCMRS), "", 0
 
208
};
 
209
 
 
210
/* Firmware data */
 
211
 
 
212
static IText   VersionT[] =
 
213
{
 
214
// AP has only versionnumber
 
215
    { "Number", "", 0, 0, 0 ,0}
 
216
};
 
217
 
 
218
static ITextVectorProperty VersionInfo = 
 
219
{
 
220
    myapdev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0
 
221
};
 
222
 
 
223
/* Mount */
 
224
 
 
225
static IText   DeclinationAxisT[] =
 
226
{
 
227
    { "RELHA", "rel. to HA", 0, 0, 0, 0} ,
 
228
};
 
229
 
 
230
static ITextVectorProperty DeclinationAxisTP = 
 
231
{
 
232
    myapdev, "DECLINATIONAXIS", "Declination axis", MOUNT_GROUP, IP_RO, 0, IPS_IDLE, DeclinationAxisT, NARRAY(DeclinationAxisT), "" ,0
 
233
};
 
234
static INumber APLocalTimeN[] = 
 
235
{
 
236
    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
 
237
};
 
238
static INumberVectorProperty APLocalTimeNP = 
 
239
{
 
240
    myapdev, "APLOCALTIME", "AP local time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APLocalTimeN, NARRAY(APLocalTimeN), "", 0
 
241
};
 
242
static INumber APSiderealTimeN[] = 
 
243
{
 
244
    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
 
245
};
 
246
static INumberVectorProperty APSiderealTimeNP = 
 
247
{
 
248
    myapdev, "APSIDEREALTIME", "AP sidereal time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APSiderealTimeN, NARRAY(APSiderealTimeN), "", 0
 
249
};
 
250
 
 
251
static INumber APUTCOffsetN[] = 
 
252
{
 
253
    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
 
254
};
 
255
static INumberVectorProperty APUTCOffsetNP = 
 
256
{
 
257
    myapdev, "APUTCOFFSET", "AP UTC Offset", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, APUTCOffsetN, NARRAY(APUTCOffsetN), "", 0
 
258
};
 
259
 
 
260
static INumber HourAxisN[] = 
 
261
{
 
262
    {"THETA",  "Theta D:M:S", "%10.6m",  0.,  360., 0., 0., 0, 0, 0}, // 0., it points to the apparent pole
 
263
    {"GAMMA",  "Gamma D:M:S", "%10.6m",  0.,  90., 0., 0., 0, 0, 0},
 
264
};
 
265
static INumberVectorProperty HourAxisNP = 
 
266
{
 
267
    myapdev, "HOURAXIS", "Hour axis", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, HourAxisN, NARRAY(HourAxisN), "", 0
 
268
};
 
269
 
 
270
/* Atmosphere */
 
271
static INumber AirN[] = 
 
272
{
 
273
    {"TEMPERATURE",  "Temperature K", "%10.2f",  0.,  383.1, 0., 283.1, 0, 0, 0},
 
274
    {"PRESSURE",  "Pressure hPa", "%10.2f",  0.,  1300., 0., 975., 0, 0, 0},
 
275
    {"HUMIDITY",  "Humidity Perc.", "%10.2f",  0.,  100., 0., 70., 0, 0, 0},
 
276
};
 
277
static INumberVectorProperty AirNP = 
 
278
{
 
279
    myapdev, "ATMOSPHERE", "Atmosphere", ATMOSPHERE_GROUP, IP_RW, 0., IPS_IDLE, AirN, NARRAY(AirN), "", 0
 
280
};
 
281
 
 
282
/* Settings Group */
 
283
static IText   ConnectionDCODT[] =
 
284
{
 
285
    { "DEVICE", "Device", 0, 0, 0, 0} ,
 
286
    { "PROPERTY", "Property", 0, 0, 0, 0}
 
287
};
 
288
static ITextVectorProperty ConnectionDCODTP = 
 
289
{
 
290
    myapdev, "SNOOPCONNECTIONDC", "Snoop dc connection", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ConnectionDCODT, NARRAY(ConnectionDCODT), "" ,0
 
291
};
 
292
static IText MasterAlarmODT[]= 
 
293
{
 
294
    { "DEVICE", "Device", 0, 0, 0, 0} ,
 
295
    { "PROPERTY", "Property", 0, 0, 0, 0}
 
296
};
 
297
static ITextVectorProperty MasterAlarmODTP = 
 
298
{
 
299
    myapdev, "SNOOPMASTERALARM", "Snoop dc master alarm", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, MasterAlarmODT, NARRAY(MasterAlarmODT), "" ,0
 
300
};
 
301
static IText   ModeDCODT[] =
 
302
{
 
303
    { "DEVICE", "Device", 0, 0, 0, 0} ,
 
304
    { "PROPERTY", "Property", 0, 0, 0, 0}
 
305
};
 
306
static ITextVectorProperty ModeDCODTP = 
 
307
{
 
308
    myapdev, "SNOOPMODEDC", "Snoop dc mode", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ModeDCODT, NARRAY(ModeDCODT), "" ,0
 
309
};
 
310
/********************************************
 
311
 Property: Park telescope to HOME
 
312
*********************************************/
 
313
 
 
314
static ISwitch ParkS[] = 
 
315
 
316
    {"PARK", "Park", ISS_OFF, 0, 0}, 
 
317
};
 
318
static ISwitchVectorProperty ParkSP = 
 
319
{
 
320
    myapdev, "TELESCOPE_PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0 
 
321
};
 
322
 
 
323
/* SNOOPed properties */
 
324
 
 
325
static ISwitch ConnectionDCS[] = 
 
326
{  
 
327
  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
 
328
  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
 
329
};
 
330
 
 
331
static ISwitchVectorProperty ConnectionDCSP = 
 
332
 
333
  "dc", "CONNECTION", "Connection", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectionDCS, NARRAY(ConnectionDCS), "", 0
 
334
};      
 
335
 
 
336
static ISwitch MasterAlarmS[] = 
 
337
{  
 
338
  {"OFF", "off", ISS_OFF, 0, 0},                         
 
339
  {"DANGER", "danger", ISS_OFF, 0, 0},
 
340
  {"ON", "ON", ISS_OFF, 0, 0},
 
341
  {"RESET", "reset", ISS_OFF, 0, 0},
 
342
};
 
343
 
 
344
static ISwitchVectorProperty MasterAlarmSP = 
 
345
 
346
  "dc", "MASTERALARM", "Master alarm", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MasterAlarmS, NARRAY(MasterAlarmS), "", 0
 
347
};
 
348
static ISwitch ModeS[] = {  
 
349
  {"MANUAL", "manual", ISS_ON, 0, 0},                         
 
350
  {"DOMECONTROL", "dome control", ISS_OFF, 0, 0}
 
351
};
 
352
 
 
353
static ISwitchVectorProperty ModeSP = { 
 
354
  "dc", "MODE", "Mode", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ModeS, NARRAY(ModeS), "", 0
 
355
};      
 
356
 
 
357
void changeLX200AstroPhysicsDeviceName(const char *newName)
 
358
{
 
359
    strcpy(VersionInfo.device, newName);
 
360
    strcpy(ParkSP.device, newName);
 
361
    strcpy(AirNP.device, newName);
 
362
    strcpy(ConnectionDCODTP.device, newName);
 
363
    strcpy(MasterAlarmODTP.device, newName);
 
364
    strcpy(ModeDCODTP.device, newName);
 
365
    strcpy(TrackModeSP.device, newName);
 
366
    strcpy(MovementNSSP.device, newName);
 
367
    strcpy(MovementWESP.device, newName);
 
368
    strcpy(MoveToRateSP.device, newName);
 
369
    strcpy(SlewRateSP.device, newName);
 
370
    strcpy(SwapSP.device, newName);
 
371
    strcpy(SyncCMRSP.device, newName);
 
372
    strcpy(DeclinationAxisTP.device, newName);
 
373
    strcpy(APLocalTimeNP.device, newName);
 
374
    strcpy(APSiderealTimeNP.device, newName);
 
375
    strcpy(HourAxisNP.device, newName);
 
376
    strcpy(APUTCOffsetNP.device, newName);
 
377
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
378
    strcpy(ApparentToObservedSP.device, newName);
 
379
#endif
 
380
    strcpy(HourangleCoordsNP.device, newName);
 
381
    strcpy(HorizontalCoordsWNP.device, newName);
 
382
    strcpy(HorizontalCoordsRNP.device, newName);
 
383
    strcpy(EquatorialCoordsWNP.device, newName);
 
384
    strcpy(EquatorialCoordsRNP.device, newName);
 
385
    strcpy(DiffEquatorialCoordsNP.device, newName);
 
386
    strcpy(StartUpSP.device, newName);
 
387
    strcpy(DomeControlSP.device, newName);
 
388
}
 
389
 
 
390
/* Constructor */
 
391
 
 
392
LX200AstroPhysics::LX200AstroPhysics() : LX200Generic()
 
393
{
 
394
    const char dev[]= "/dev/apmount" ;
 
395
    const char status[]= "undefined" ;
 
396
    IUSaveText(&ConnectionDCODT[0], ConnectionDCSP.device);
 
397
    IUSaveText(&ConnectionDCODT[1], ConnectionDCSP.name);
 
398
    IUSaveText(&MasterAlarmODT[0], MasterAlarmSP.device);
 
399
    IUSaveText(&MasterAlarmODT[1], MasterAlarmSP.name);
 
400
    IUSaveText(&ModeDCODT[0], ModeSP.device);
 
401
    IUSaveText(&ModeDCODT[1], ModeSP.name);
 
402
 
 
403
 
 
404
    IUSaveText(&PortTP.tp[0], dev);
 
405
    IUSaveText(&DeclinationAxisTP.tp[0], status);
 
406
}
 
407
void LX200AstroPhysics::ISGetProperties (const char *dev)
 
408
{
 
409
    if (dev && strcmp (thisDevice, dev))
 
410
        return;
 
411
 
 
412
    LX200Generic::ISGetProperties(dev);
 
413
 
 
414
    IDDelete(thisDevice, "TELESCOPE_PARK", NULL);
 
415
    IDDefSwitch (&ParkSP, NULL);
 
416
    IDDefText(&VersionInfo, NULL);
 
417
 
 
418
/* Communication group */
 
419
 
 
420
    // AstroPhysics has no alignment mode
 
421
    IDDelete(thisDevice, "Alignment", NULL);
 
422
    IDDefSwitch (&StartUpSP, NULL);
 
423
    IDDefSwitch (&DomeControlSP, NULL);
 
424
 
 
425
/* Main Group */
 
426
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
427
    IDDefSwitch(&ApparentToObservedSP, NULL);
 
428
#endif
 
429
    IDDefNumber(&HourangleCoordsNP, NULL) ;
 
430
    IDDefNumber(&HorizontalCoordsWNP, NULL);
 
431
    IDDefNumber(&HorizontalCoordsRNP, NULL);
 
432
    IDDelete(thisDevice, "EQUATORIAL_EOD_COORD_REQUEST", NULL);
 
433
    IDDelete(thisDevice, "EQUATORIAL_EOD_COORD", NULL);
 
434
    IDDefNumber(&EquatorialCoordsWNP, NULL);
 
435
    IDDefNumber(&EquatorialCoordsRNP, NULL);
 
436
    IDDefNumber(&DiffEquatorialCoordsNP, NULL);
 
437
/* Date&Time group */
 
438
    IDDelete(thisDevice, "TIME_UTC_OFFSET", NULL);
 
439
    IDDefText(&DeclinationAxisTP, NULL);
 
440
/* Mount group */
 
441
 
 
442
    IDDefText(&DeclinationAxisTP, NULL);
 
443
    IDDefNumber(&APLocalTimeNP, NULL);
 
444
    IDDefNumber(&APSiderealTimeNP, NULL);
 
445
    IDDefNumber(&APUTCOffsetNP, NULL);
 
446
    IDDefNumber(&HourAxisNP, NULL);
 
447
 
 
448
/* Atmosphere group */
 
449
 
 
450
    IDDefNumber   (&AirNP, NULL);
 
451
 
 
452
/* Settings group */
 
453
 
 
454
    IDDefText   (&ConnectionDCODTP, NULL);
 
455
    IDDefText   (&MasterAlarmODTP, NULL);
 
456
    IDDefText   (&ModeDCODTP, NULL);
 
457
 
 
458
    // AstroPhysics, we have no focuser, therefore, we don't need the classical one
 
459
    IDDelete(thisDevice, "FOCUS_MODE", NULL);
 
460
    IDDelete(thisDevice, "FOCUS_MOTION", NULL);
 
461
    IDDelete(thisDevice, "FOCUS_TIMER", NULL);
 
462
 
 
463
/* Motion group */
 
464
    IDDelete(thisDevice, "Slew rate", NULL);
 
465
    IDDelete(thisDevice, "Tracking Mode", NULL);
 
466
    IDDelete(thisDevice, "Tracking Frequency", NULL); /* AP does not have :GT, :ST commands */
 
467
 
 
468
    IDDefSwitch (&TrackModeSP, NULL);
 
469
    IDDefSwitch (&MovementNSSP, NULL);
 
470
    IDDefSwitch (&MovementWESP, NULL);
 
471
    IDDefSwitch (&MoveToRateSP, NULL);
 
472
    IDDefSwitch (&SlewRateSP, NULL);
 
473
    IDDefSwitch (&SwapSP, NULL);
 
474
    IDDefSwitch (&SyncCMRSP, NULL);
 
475
 
 
476
/* Site management */
 
477
    /* Astro Physics has no commands to retrieve the values */
 
478
    /* True for all three control boxes and the software  and C-KE1, G-L*/
 
479
    IDDelete(thisDevice, "Sites", NULL);
 
480
    IDDelete(thisDevice, "Site Name", NULL);
 
481
 
 
482
}
 
483
 
 
484
void LX200AstroPhysics::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
 
485
{
 
486
    IText *tp=NULL;
 
487
 
 
488
    // ignore if not ours //
 
489
    if (strcmp (dev, thisDevice))
 
490
        return;
 
491
 
 
492
    // ===================================
 
493
    // Snoop DC Connection
 
494
    // ===================================
 
495
    if (!strcmp(name, ConnectionDCODTP.name) )
 
496
    {
 
497
        tp = IUFindText( &ConnectionDCODTP, names[0] );
 
498
        if (!tp)
 
499
            return;
 
500
 
 
501
        IUSaveText(tp, texts[0]);
 
502
        tp = IUFindText( &ConnectionDCODTP, names[1] );
 
503
        if (!tp)
 
504
            return;
 
505
 
 
506
        ConnectionDCODTP.s = IPS_OK;
 
507
        IUSaveText(tp, texts[1]);
 
508
 
 
509
        IDSnoopDevice( ConnectionDCODT[0].text, ConnectionDCODT[1].text);
 
510
 
 
511
        ConnectionDCODTP.s= IPS_OK ;
 
512
        IDSetText (&ConnectionDCODTP, "Snooping property %s at device %s", ConnectionDCODT[1].text, ConnectionDCODT[0].text);
 
513
        return;
 
514
    }
 
515
 
 
516
    // ===================================
 
517
    // Master Alarm
 
518
    // ===================================
 
519
    if (!strcmp(name, MasterAlarmODTP.name) )
 
520
    {
 
521
        tp = IUFindText( &MasterAlarmODTP, names[0] );
 
522
        if (!tp)
 
523
            return;
 
524
            
 
525
        IUSaveText(tp, texts[0]);
 
526
 
 
527
        tp = IUFindText( &MasterAlarmODTP, names[1] );
 
528
        if (!tp)
 
529
            return;
 
530
        IUSaveText(tp, texts[1]);
 
531
 
 
532
        IDSnoopDevice( MasterAlarmODT[0].text, MasterAlarmODT[1].text);
 
533
 
 
534
        MasterAlarmODTP.s= IPS_OK ;
 
535
        IDSetText (&MasterAlarmODTP, "Snooping property %s at device %s", MasterAlarmODT[1].text, MasterAlarmODT[0].text) ;
 
536
        return;
 
537
    }
 
538
 
 
539
    // ===================================
 
540
    // Snope DC Mode
 
541
    // ===================================
 
542
    if (!strcmp(name, ModeDCODTP.name) )
 
543
    {
 
544
        tp = IUFindText( &ModeDCODTP, names[0] );
 
545
        if (!tp)
 
546
            return;
 
547
 
 
548
        IUSaveText(tp, texts[0]);
 
549
        tp = IUFindText( &ModeDCODTP, names[1] );
 
550
        if (!tp)
 
551
            return;
 
552
 
 
553
        ModeDCODTP.s = IPS_OK;
 
554
        IUSaveText(tp, texts[1]);
 
555
 
 
556
        IDSnoopDevice( ModeDCODT[0].text, ModeDCODT[1].text);
 
557
 
 
558
        ModeDCODTP.s= IPS_OK ;
 
559
        IDSetText (&ModeDCODTP, "Snooping property %s at device %s", ModeDCODT[1].text, ModeDCODT[0].text);
 
560
        return;
 
561
    }
 
562
 
 
563
    LX200Generic::ISNewText (dev, name, texts, names, n);
 
564
}
 
565
 
 
566
 
 
567
void LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
 
568
{
 
569
    int i=0, nset=0;
 
570
    INumber *np=NULL;
 
571
 
 
572
    // ignore if not ours
 
573
    if (strcmp (dev, thisDevice))
 
574
            return;
 
575
 
 
576
    // ===================================
 
577
    // Atmosphere
 
578
    // ===================================
 
579
    if (!strcmp (name, AirNP.name))
 
580
    {
 
581
        double newTemperature ;
 
582
        double newPressure ;
 
583
        double newHumidity ;
 
584
        if (checkPower(&AirNP))
 
585
            return;
 
586
 
 
587
        for (nset = i = 0; i < n; i++)
 
588
        {
 
589
            np = IUFindNumber (&AirNP, names[i]);
 
590
            if( np == &AirN[0])
 
591
            {
 
592
                newTemperature = values[i];
 
593
                nset++ ;
 
594
            } 
 
595
            else if( np == &AirN[1])
 
596
            {
 
597
                newPressure = values[i];
 
598
                nset++ ;
 
599
            }
 
600
            else if( np == &AirN[2])
 
601
            {
 
602
                newHumidity = values[i];
 
603
                nset++  ;
 
604
            }
 
605
        }
 
606
 
 
607
        if (nset == 3)
 
608
        {
 
609
            AirNP.s = IPS_OK;
 
610
            AirN[0].value = newTemperature;
 
611
            AirN[1].value = newPressure;
 
612
            AirN[2].value = newHumidity;
 
613
 
 
614
            IDSetNumber(&AirNP, NULL);
 
615
        } 
 
616
        else
 
617
        {
 
618
            AirNP.s = IPS_ALERT;
 
619
            IDSetNumber(&AirNP, "Temperature, Pressure or Humidity missing or invalid");
 
620
        }
 
621
        return;
 
622
    }
 
623
 
 
624
    // ===================================
 
625
    // AP UTC Offset
 
626
    // ===================================
 
627
    if ( !strcmp (name, APUTCOffsetNP.name) )
 
628
    {
 
629
        int ret ;
 
630
        if (checkPower(&APUTCOffsetNP))
 
631
            return;
 
632
 
 
633
        if (values[0] <= 0.0 || values[0] > 24.0)
 
634
        {
 
635
            APUTCOffsetNP.s = IPS_IDLE;
 
636
            IDSetNumber(&APUTCOffsetNP , "UTC offset invalid");
 
637
            return;
 
638
        }
 
639
 
 
640
        if(( ret = setAPUTCOffset(fd, values[0]) < 0) )
 
641
        {
 
642
            handleError(&APUTCOffsetNP, ret, "Setting AP UTC offset");
 
643
            return;
 
644
        }
 
645
 
 
646
        APUTCOffsetN[0].value = values[0];
 
647
        APUTCOffsetNP.s = IPS_OK;
 
648
 
 
649
        IDSetNumber(&APUTCOffsetNP, NULL);
 
650
 
 
651
        return;
 
652
    }
 
653
 
 
654
    // =======================================
 
655
    // Hour axis' intersection with the sphere
 
656
    // =======================================
 
657
    if (!strcmp (name, HourAxisNP.name))
 
658
    {
 
659
        int i=0, nset=0;
 
660
        double newTheta, newGamma ;
 
661
 
 
662
        if (checkPower(&HourAxisNP))
 
663
            return;
 
664
 
 
665
        for (nset = i = 0; i < n; i++)
 
666
        {
 
667
            np = IUFindNumber (&HourAxisNP, names[i]);
 
668
            if ( np == &HourAxisN[0])
 
669
            {
 
670
                newTheta = values[i];
 
671
                nset += newTheta >= 0 && newTheta <= 360.0;
 
672
            }
 
673
            else if ( np == &HourAxisN[1])
 
674
            {
 
675
                newGamma = values[i];
 
676
                nset += newGamma >= 0. && newGamma <= 90.0;
 
677
            }
 
678
        }
 
679
 
 
680
        if (nset == 2)
 
681
        {
 
682
            HourAxisNP.s = IPS_OK;
 
683
            HourAxisN[0].value = newTheta;
 
684
            HourAxisN[1].value = newGamma;
 
685
            IDSetNumber(&HourAxisNP, NULL);
 
686
        }
 
687
        else
 
688
        {
 
689
            HourAxisNP.s = IPS_ALERT;
 
690
            IDSetNumber(&HourAxisNP, "Theta or gamma missing or invalid");
 
691
        }
 
692
 
 
693
        return;
 
694
    }
 
695
 
 
696
    // =======================================
 
697
    // Equatorial Coord - SET
 
698
    // =======================================
 
699
    if (!strcmp (name, EquatorialCoordsWNP.name))
 
700
    {
 
701
        int err ;
 
702
        int i=0, nset=0;
 
703
        double newRA, newDEC ;
 
704
        if (checkPower(&EquatorialCoordsWNP))
 
705
            return;
 
706
 
 
707
        for (nset = i = 0; i < n; i++)
 
708
        {
 
709
            INumber *np = IUFindNumber (&EquatorialCoordsWNP, names[i]);
 
710
            if (np == &EquatorialCoordsWNP.np[0])
 
711
            {
 
712
                newRA = values[i];
 
713
                nset += newRA >= 0 && newRA <= 24.0;
 
714
            } else if (np == &EquatorialCoordsWNP.np[1])
 
715
            {
 
716
                newDEC = values[i];
 
717
                nset += newDEC >= -90.0 && newDEC <= 90.0;
 
718
            }
 
719
        }
 
720
 
 
721
        if (nset == 2)
 
722
        {
 
723
            int ret ;
 
724
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
725
 
 
726
            double geo[6] ;
 
727
            double eqt[2] ;
 
728
            double eqn[2] ;
 
729
            double hxt[2] ;
 
730
#endif 
 
731
            /*EquatorialCoordsWNP.s = IPS_BUSY;*/
 
732
            char RAStr[32], DecStr[32];
 
733
 
 
734
            fs_sexa(RAStr, newRA, 2, 3600);
 
735
            fs_sexa(DecStr, newDEC, 2, 3600);
 
736
 
 
737
#ifdef INDI_DEBUG
 
738
            IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
 
739
            IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
 
740
#endif
 
741
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
742
            // Transfor the coordinates
 
743
            /* Get the current time. */
 
744
            geo[0]= geoNP.np[0].value ;
 
745
            geo[1]= geoNP.np[1].value ;
 
746
            geo[2]= geoNP.np[2].value ;
 
747
            geo[3]= AirN[0].value ;
 
748
            geo[4]= AirN[1].value ;
 
749
            geo[5]= AirN[2].value ;
 
750
 
 
751
            eqn[0]= newRA ;
 
752
            eqn[1]= newDEC ;
 
753
            hxt[0]= HourAxisN[0].value ;
 
754
            hxt[1]= HourAxisN[1].value ;
 
755
 
 
756
            if((ret = LDAppToX(  getOnSwitch(&ApparentToObservedSP), eqn, ln_get_julian_from_sys(), geo, hxt, eqt)) != 0)
 
757
            {
 
758
                IDMessage( myapdev, "ISNewNumber: transformation %d failed", getOnSwitch(&ApparentToObservedSP)) ;
 
759
                exit(1) ;
 
760
            } ;
 
761
            /*EquatorialCoordsWNP.s = IPS_BUSY;*/
 
762
            targetRA= eqt[0];
 
763
            targetDEC= eqt[1];
 
764
#else
 
765
            targetRA= newRA;
 
766
            targetDEC= newDEC;
 
767
#endif
 
768
            if ( (ret = setAPObjectRA(fd, targetRA)) < 0 || ( ret = setAPObjectDEC(fd, targetDEC)) < 0)
 
769
            {
 
770
                DiffEquatorialCoordsNP.s= IPS_ALERT;
 
771
                IDSetNumber(&DiffEquatorialCoordsNP, NULL);
 
772
                handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC");
 
773
                return;
 
774
            }
 
775
            EquatorialCoordsWNP.s = IPS_OK;
 
776
            IDSetNumber(&EquatorialCoordsWNP, NULL);
 
777
 
 
778
            DiffEquatorialCoordsNP.np[0].value= targetRA - currentRA ;
 
779
            DiffEquatorialCoordsNP.np[1].value= targetDEC - currentDEC;
 
780
            DiffEquatorialCoordsNP.s= IPS_OK;
 
781
            IDSetNumber(&DiffEquatorialCoordsNP, NULL);
 
782
 
 
783
            // ToDo don't we need to stop the motion (:Q#)?
 
784
            if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
 
785
            {
 
786
                IUResetSwitch(&MovementNSSP);
 
787
                IUResetSwitch(&MovementWESP);
 
788
                MovementNSSP.s = MovementWESP.s = IPS_IDLE;
 
789
                IDSetSwitch(&MovementNSSP, NULL);
 
790
                IDSetSwitch(&MovementWESP, NULL);
 
791
            }
 
792
            handleEqCoordSet() ;
 
793
//ToDo : conversion to boolean      {
 
794
//              EquatorialCoordsWNP.s = IPS_ALERT;
 
795
//              IDSetNumber(&EquatorialCoordsWNP, NULL);
 
796
 
 
797
//          }
 
798
        } // end nset
 
799
        else
 
800
        {
 
801
            EquatorialCoordsWNP.s = IPS_ALERT;
 
802
            IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
 
803
        }
 
804
        return ;
 
805
    }
 
806
 
 
807
    // =======================================
 
808
    // Horizontal Coords - SET
 
809
    // =======================================
 
810
    if ( !strcmp (name, HorizontalCoordsWNP.name) )
 
811
    {
 
812
        int i=0, nset=0;
 
813
        double newAz, newAlt ;
 
814
        int ret ;
 
815
        char altStr[64], azStr[64];
 
816
 
 
817
        if (checkPower(&HorizontalCoordsWNP))
 
818
            return;
 
819
 
 
820
        for (nset = i = 0; i < n; i++)
 
821
        {
 
822
            np = IUFindNumber (&HorizontalCoordsWNP, names[i]);
 
823
            if (np == &HorizontalCoordsWN[0])
 
824
            {
 
825
                newAz = values[i];
 
826
                nset += newAz >= 0. && newAz <= 360.0;
 
827
            } 
 
828
            else if (np == &HorizontalCoordsWN[1])
 
829
            {
 
830
                newAlt = values[i];
 
831
                nset += newAlt >= -90. && newAlt <= 90.0;
 
832
            }
 
833
        }
 
834
        if (nset == 2)
 
835
        {
 
836
            if ( (ret = setAPObjectAZ(fd, newAz)) < 0 || (ret = setAPObjectAlt(fd, newAlt)) < 0)
 
837
            {
 
838
                handleError(&HorizontalCoordsWNP, ret, "Setting Alt/Az");
 
839
                return;
 
840
            }
 
841
            targetAZ= newAz;
 
842
            targetALT= newAlt;
 
843
            HorizontalCoordsWNP.s = IPS_OK;
 
844
            IDSetNumber(&HorizontalCoordsWNP, NULL) ;
 
845
 
 
846
            fs_sexa(azStr, targetAZ, 2, 3600);
 
847
            fs_sexa(altStr, targetALT, 2, 3600);
 
848
 
 
849
            //IDSetNumber (&HorizontalCoordsWNP, "Attempting to slew to Alt %s - Az %s", altStr, azStr);
 
850
            handleAltAzSlew();
 
851
        }
 
852
        else
 
853
        {
 
854
            HorizontalCoordsWNP.s = IPS_ALERT;
 
855
            IDSetNumber(&HorizontalCoordsWNP, "Altitude or Azimuth missing or invalid");
 
856
        }
 
857
 
 
858
        return;
 
859
    }
 
860
 
 
861
    // =======================================
 
862
    // Geographical Location
 
863
    // =======================================
 
864
    if (!strcmp (name, geoNP.name))
 
865
    {
 
866
        // new geographic coords
 
867
        double newLong = 0, newLat = 0;
 
868
        int i, nset, err;
 
869
        char msg[128];
 
870
 
 
871
        if (checkPower(&geoNP))
 
872
            return;
 
873
 
 
874
        for (nset = i = 0; i < n; i++)
 
875
        {
 
876
            np = IUFindNumber (&geoNP, names[i]);
 
877
            if (np == &geoNP.np[0])
 
878
            {
 
879
                newLat = values[i];
 
880
                nset += newLat >= -90.0 && newLat <= 90.0;
 
881
            } else if (np == &geoNP.np[1])
 
882
            {
 
883
                newLong = values[i];
 
884
                nset += newLong >= 0.0 && newLong < 360.0;
 
885
            }
 
886
        }
 
887
 
 
888
        if (nset == 2)
 
889
        {
 
890
            char l[32], L[32];
 
891
            geoNP.s = IPS_OK;
 
892
            fs_sexa (l, newLat, 3, 3600);
 
893
            fs_sexa (L, newLong, 4, 3600);
 
894
            
 
895
            if ( ( err = setAPSiteLongitude(fd, 360.0 - newLong) < 0) )
 
896
            {
 
897
                handleError(&geoNP, err, "Setting site coordinates");
 
898
                return;
 
899
            }
 
900
            if ( ( err = setAPSiteLatitude(fd, newLat) < 0) )
 
901
            {
 
902
                handleError(&geoNP, err, "Setting site coordinates");
 
903
                return;
 
904
            }
 
905
 
 
906
            geoNP.np[0].value = newLat;
 
907
            geoNP.np[1].value = newLong;
 
908
            snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
 
909
        } 
 
910
        else
 
911
        {
 
912
            geoNP.s = IPS_IDLE;
 
913
            strcpy(msg, "Lat or Long missing or invalid");
 
914
        }
 
915
        IDSetNumber (&geoNP, "%s", msg);
 
916
        return;
 
917
    }
 
918
 
 
919
    LX200Generic::ISNewNumber (dev, name, values, names, n);
 
920
}
 
921
 
 
922
void LX200AstroPhysics::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
 
923
{
 
924
    int err=0;
 
925
 
 
926
    // ignore if not ours //
 
927
    if (strcmp (thisDevice, dev))
 
928
            return;
 
929
 
 
930
    // =======================================
 
931
    // Connect
 
932
    // =======================================
 
933
    if (!strcmp (name, ConnectSP.name))
 
934
    {
 
935
        IUUpdateSwitch(&ConnectSP, states, names, n) ;
 
936
 
 
937
        connectTelescope();
 
938
        return;
 
939
    }
 
940
 
 
941
    // ============================================================
 
942
    // Satisfy AP mount initialization, see AP key pad manual p. 76
 
943
    // ============================================================
 
944
    if (!strcmp (name, StartUpSP.name))
 
945
    {
 
946
        int ret ;
 
947
        int switch_nr ;
 
948
        static int mount_status= MOUNTNOTINITIALIZED ;
 
949
 
 
950
        IUUpdateSwitch(&StartUpSP, states, names, n) ;
 
951
 
 
952
        if( mount_status == MOUNTNOTINITIALIZED)
 
953
        {
 
954
            mount_status=MOUNTINITIALIZED;
 
955
        
 
956
            if(( ret= setBasicDataPart0())< 0)
 
957
            {
 
958
                // ToDo do something if needed
 
959
                StartUpSP.s = IPS_ALERT ;
 
960
                IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
 
961
                return ;
 
962
            }
 
963
            if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start) 
 
964
            {
 
965
                if(( ret= setBasicDataPart1())< 0)
 
966
                {
 
967
                    // ToDo do something if needed
 
968
                    StartUpSP.s = IPS_ALERT ;
 
969
                    IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
 
970
                    return ;
 
971
                }
 
972
            }
 
973
            // Make sure that the mount is setup according to the properties        
 
974
            switch_nr = getOnSwitch(&TrackModeSP);
 
975
 
 
976
            if ( ( err = selectAPTrackingMode(fd, switch_nr) < 0) )
 
977
            {
 
978
                handleError(&TrackModeSP, err, "StartUpSP: Setting tracking mode.");
 
979
                return;
 
980
            }
 
981
            TrackModeSP.s = IPS_OK;
 
982
            IDSetSwitch(&TrackModeSP, NULL);
 
983
            //ToDo set button swapping acording telescope east west
 
984
            // ... some code here
 
985
 
 
986
            switch_nr = getOnSwitch(&MoveToRateSP);
 
987
          
 
988
            if ( ( err = selectAPMoveToRate(fd, switch_nr) < 0) )
 
989
            {
 
990
                handleError(&MoveToRateSP, err, "StartUpSP: Setting move to rate.");
 
991
                return;
 
992
            }
 
993
            MoveToRateSP.s = IPS_OK;
 
994
 
 
995
            IDSetSwitch(&MoveToRateSP, NULL);
 
996
            switch_nr = getOnSwitch(&SlewRateSP);
 
997
          
 
998
            if ( ( err = selectAPSlewRate(fd, switch_nr) < 0) )
 
999
            {
 
1000
                handleError(&SlewRateSP, err, "StartUpSP: Setting slew rate.");
 
1001
                return;
 
1002
            }
 
1003
            SlewRateSP.s = IPS_OK;
 
1004
            IDSetSwitch(&SlewRateSP, NULL);
 
1005
 
 
1006
            StartUpSP.s = IPS_OK ;
 
1007
            IDSetSwitch(&StartUpSP, "Mount initialized") ;
 
1008
            // Fetch the coordinates and set RNP and WNP
 
1009
            getLX200RA( fd, &currentRA); 
 
1010
            getLX200DEC(fd, &currentDEC);
 
1011
 
 
1012
            // make a IDSet in order the dome controller is aware of the initial values
 
1013
            targetRA= currentRA ;
 
1014
            targetDEC= currentDEC ;
 
1015
            EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
 
1016
            IDSetNumber(&EquatorialCoordsWNP,  "EquatorialCoordsWNP.s = IPS_BUSY after initialization");
 
1017
 
 
1018
            // sleep for 100 mseconds
 
1019
            usleep(100000);
 
1020
 
 
1021
            EquatorialCoordsWNP.s = IPS_OK; 
 
1022
            IDSetNumber(&EquatorialCoordsWNP, NULL);
 
1023
 
 
1024
            getLX200Az(fd, &currentAZ);
 
1025
            getLX200Alt(fd, &currentALT);
 
1026
 
 
1027
            HorizontalCoordsRNP.s = IPS_OK ;
 
1028
            IDSetNumber (&HorizontalCoordsRNP, NULL);
 
1029
 
 
1030
            VersionInfo.tp[0].text = new char[64];
 
1031
            getAPVersionNumber(fd, VersionInfo.tp[0].text);
 
1032
 
 
1033
            VersionInfo.s = IPS_OK ;
 
1034
            IDSetText(&VersionInfo, NULL);
 
1035
 
 
1036
            if(( getOnSwitch(&DomeControlSP))== DOMECONTROL)
 
1037
            {
 
1038
                //ToDo compare that with other driver, not the best way
 
1039
                IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text);
 
1040
                MasterAlarmODTP.s= IPS_OK ;
 
1041
                IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text);
 
1042
 
 
1043
                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
 
1044
                ConnectionDCODTP.s= IPS_OK ;
 
1045
                IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text);
 
1046
                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
 
1047
 
 
1048
                IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text);
 
1049
                ModeDCODTP.s= IPS_OK ;
 
1050
                IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text);
 
1051
 
 
1052
                // once chosen no unsnooping is possible
 
1053
                DomeControlSP.s= IPS_OK ;
 
1054
                IDSetSwitch(&DomeControlSP, NULL) ;
 
1055
            }
 
1056
            else
 
1057
            {
 
1058
                IDMessage( myapdev, "Not operating in dome control mode") ;
 
1059
            }
 
1060
             #ifndef HAVE_NOVA_H
 
1061
            IDMessage( myapdev, "Libnova not compiled in, consider to install it (http://libnova.sourceforge.net/)") ;
 
1062
            #endif
 
1063
            #ifndef HAVE_NOVASCC_H
 
1064
            IDMessage( myapdev, "NOVASCC not compiled in, consider to install it (http://aa.usno.navy.mil/AA/)") ;
 
1065
            #endif
 
1066
        }
 
1067
        else
 
1068
        {
 
1069
            StartUpSP.s = IPS_ALERT ;
 
1070
            IDSetSwitch(&StartUpSP, "Mount is already initialized") ;
 
1071
        }
 
1072
        return;
 
1073
    }
 
1074
 
 
1075
    // =======================================
 
1076
    // Park
 
1077
    // =======================================
 
1078
    if (!strcmp(name, ParkSP.name))
 
1079
    {
 
1080
        if (checkPower(&ParkSP))
 
1081
            return;
 
1082
        
 
1083
        if (EquatorialCoordsWNP.s == IPS_BUSY)
 
1084
        {
 
1085
            // ToDo handle return value
 
1086
            abortSlew(fd);
 
1087
            // sleep for 200 mseconds
 
1088
            usleep(200000);
 
1089
            AbortSlewSP.s = IPS_OK;
 
1090
            IDSetSwitch(&AbortSlewSP, NULL);
 
1091
 
 
1092
        }
 
1093
 
 
1094
        if (setAPPark(fd) < 0)
 
1095
        {
 
1096
            ParkSP.s = IPS_ALERT;
 
1097
            IDSetSwitch(&ParkSP, "Parking Failed.");
 
1098
            return;
 
1099
        }
 
1100
 
 
1101
        ParkSP.s = IPS_OK;
 
1102
        IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting...");
 
1103
        // avoid sending anything to the mount controller
 
1104
        tty_disconnect( fd);
 
1105
        ConnectSP.s   = IPS_IDLE;
 
1106
        ConnectSP.sp[0].s = ISS_OFF;
 
1107
        ConnectSP.sp[1].s = ISS_ON;
 
1108
        
 
1109
        IDSetSwitch(&ConnectSP, NULL);
 
1110
 
 
1111
        StartUpSP.s = IPS_IDLE ;
 
1112
        IDSetSwitch(&StartUpSP, NULL) ;
 
1113
 
 
1114
        // ToDo reset all values
 
1115
 
 
1116
        return;
 
1117
    }
 
1118
 
 
1119
    // =======================================
 
1120
    // Tracking Mode
 
1121
    // =======================================
 
1122
    if (!strcmp (name, TrackModeSP.name))
 
1123
    {
 
1124
        if (checkPower(&TrackModeSP))
 
1125
            return;
 
1126
 
 
1127
        IUResetSwitch(&TrackModeSP);
 
1128
        IUUpdateSwitch(&TrackModeSP, states, names, n);
 
1129
        trackingMode = getOnSwitch(&TrackModeSP);
 
1130
          
 
1131
        if ( ( err = selectAPTrackingMode(fd, trackingMode) < 0) )
 
1132
        {
 
1133
            handleError(&TrackModeSP, err, "Setting tracking mode.");
 
1134
            return;
 
1135
        }     
 
1136
        TrackModeSP.s = IPS_OK;
 
1137
        IDSetSwitch(&TrackModeSP, NULL);
 
1138
        if( trackingMode != 3) /* not zero */
 
1139
        {
 
1140
            AbortSlewSP.s = IPS_IDLE;
 
1141
            IDSetSwitch(&AbortSlewSP, NULL);
 
1142
        }
 
1143
        return;
 
1144
    }
 
1145
 
 
1146
    // =======================================
 
1147
    // Swap Buttons
 
1148
    // =======================================
 
1149
    if (!strcmp(name, SwapSP.name))
 
1150
    {
 
1151
        int currentSwap ;
 
1152
 
 
1153
        if (checkPower(&SwapSP))
 
1154
            return;
 
1155
        
 
1156
        IUResetSwitch(&SwapSP);
 
1157
        IUUpdateSwitch(&SwapSP, states, names, n);
 
1158
        currentSwap = getOnSwitch(&SwapSP);
 
1159
 
 
1160
        if(( err = swapAPButtons(fd, currentSwap) < 0) )
 
1161
        {
 
1162
            handleError(&SwapSP, err, "Swapping buttons.");
 
1163
            return;
 
1164
        }
 
1165
 
 
1166
        SwapS[0].s= ISS_OFF ;
 
1167
        SwapS[1].s= ISS_OFF ;
 
1168
        SwapSP.s = IPS_OK;
 
1169
        IDSetSwitch(&SwapSP, NULL);
 
1170
        return ;
 
1171
    }
 
1172
 
 
1173
    // =======================================
 
1174
    // Swap to rate
 
1175
    // =======================================
 
1176
    if (!strcmp (name, MoveToRateSP.name))
 
1177
    {
 
1178
        int moveToRate ;
 
1179
 
 
1180
        if (checkPower(&MoveToRateSP))
 
1181
            return;
 
1182
 
 
1183
        IUResetSwitch(&MoveToRateSP);
 
1184
        IUUpdateSwitch(&MoveToRateSP, states, names, n);
 
1185
        moveToRate = getOnSwitch(&MoveToRateSP);
 
1186
          
 
1187
        if ( ( err = selectAPMoveToRate(fd, moveToRate) < 0) )
 
1188
        {
 
1189
            handleError(&MoveToRateSP, err, "Setting move to rate.");
 
1190
            return;
 
1191
        }
 
1192
        MoveToRateSP.s = IPS_OK;
 
1193
        IDSetSwitch(&MoveToRateSP, NULL);
 
1194
        return;
 
1195
    }
 
1196
 
 
1197
    // =======================================
 
1198
    // Slew Rate
 
1199
    // =======================================
 
1200
    if (!strcmp (name, SlewRateSP.name))
 
1201
    {
 
1202
        int slewRate ;
 
1203
        
 
1204
        if (checkPower(&SlewRateSP))
 
1205
            return;
 
1206
 
 
1207
        IUResetSwitch(&SlewRateSP);
 
1208
        IUUpdateSwitch(&SlewRateSP, states, names, n);
 
1209
        slewRate = getOnSwitch(&SlewRateSP);
 
1210
          
 
1211
        if ( ( err = selectAPSlewRate(fd, slewRate) < 0) )
 
1212
        {
 
1213
            handleError(&SlewRateSP, err, "Setting slew rate.");
 
1214
            return;
 
1215
        }
 
1216
          
 
1217
          
 
1218
        SlewRateSP.s = IPS_OK;
 
1219
        IDSetSwitch(&SlewRateSP, NULL);
 
1220
        return;
 
1221
    }
 
1222
 
 
1223
    // =======================================
 
1224
    // Choose the appropriate sync command
 
1225
    // =======================================
 
1226
    if (!strcmp(name, SyncCMRSP.name))
 
1227
    {
 
1228
        int currentSync ;
 
1229
        if (checkPower(&SyncCMRSP))
 
1230
            return;
 
1231
 
 
1232
        IUResetSwitch(&SyncCMRSP);
 
1233
        IUUpdateSwitch(&SyncCMRSP, states, names, n);
 
1234
        currentSync = getOnSwitch(&SyncCMRSP);
 
1235
        SyncCMRSP.s = IPS_OK;
 
1236
        IDSetSwitch(&SyncCMRSP, NULL);
 
1237
        return ;
 
1238
    }
 
1239
 
 
1240
    #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
 
1241
    // =======================================
 
1242
    // Set various transformations
 
1243
    // =======================================
 
1244
    if (!strcmp (name, ApparentToObservedSP.name))
 
1245
    {
 
1246
        int trans_to ;
 
1247
        if (checkPower(&ApparentToObservedSP))
 
1248
            return;
 
1249
 
 
1250
        IUResetSwitch(&ApparentToObservedSP);
 
1251
        IUUpdateSwitch(&ApparentToObservedSP, states, names, n);
 
1252
        trans_to = getOnSwitch(&ApparentToObservedSP);
 
1253
 
 
1254
        ApparentToObservedSP.s = IPS_OK;
 
1255
        IDSetSwitch(&ApparentToObservedSP, "Transformation %d", trans_to);
 
1256
        return;
 
1257
    }
 
1258
    #endif
 
1259
    if (!strcmp (name, DomeControlSP.name))
 
1260
    {
 
1261
        if((DomeControlSP.s== IPS_OK) &&( DomeControlSP.sp[0].s== ISS_ON))
 
1262
        {
 
1263
    #ifdef INDI_DEBUG
 
1264
            IDLog("Once in dome control mode no return is possible (INDI has no \"unsnoop\")\n") ;
 
1265
    #endif
 
1266
            DomeControlSP.s= IPS_ALERT ;
 
1267
            IDSetSwitch(&DomeControlSP, "Once in dome control mode no return is possible (INDI has no \"unsnoop\")") ;
 
1268
        }
 
1269
        else
 
1270
        {
 
1271
            int last_state= getOnSwitch(&DomeControlSP) ;
 
1272
            IUResetSwitch(&DomeControlSP);
 
1273
            IUUpdateSwitch(&DomeControlSP, states, names, n) ;
 
1274
            DomeControlSP.s= IPS_OK ;
 
1275
            IDSetSwitch(&DomeControlSP, NULL) ;
 
1276
 
 
1277
            if(( DomeControlSP.s== IPS_OK) &&( last_state== NOTDOMECONTROL)) /* dome control mode after mount init. */
 
1278
            {
 
1279
                //ToDo compare that with other driver, not the best way
 
1280
                IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text);
 
1281
                MasterAlarmODTP.s= IPS_OK ;
 
1282
                IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text);
 
1283
 
 
1284
                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
 
1285
                ConnectionDCODTP.s= IPS_OK ;
 
1286
                IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text);
 
1287
                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
 
1288
 
 
1289
                IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text);
 
1290
                ModeDCODTP.s= IPS_OK ;
 
1291
                IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text);
 
1292
            }
 
1293
        }
 
1294
        return;
 
1295
    }
 
1296
 
 
1297
    LX200Generic::ISNewSwitch (dev, name, states, names,  n);
 
1298
 }
 
1299
void LX200AstroPhysics::ISSnoopDevice (XMLEle *root)
 
1300
{
 
1301
    int err ;
 
1302
    if (IUSnoopSwitch(root, &MasterAlarmSP) == 0)
 
1303
    {
 
1304
        //IDMessage( myapdev, "ISCollisionStatusS received new values %s: %d, %s: %d, %s: %d.", names[0], states[0],names[1], states[1],names[2], states[2]);
 
1305
        if( MasterAlarmS[1].s == ISS_ON) /* Approaching a critical situation */
 
1306
        {
 
1307
/* Stop if possible any motion */
 
1308
            // ToDo
 
1309
            abortSlew(fd);
 
1310
            AbortSlewSP.s = IPS_OK;
 
1311
            IDSetSwitch(&AbortSlewSP, NULL);
 
1312
 
 
1313
            if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
 
1314
            {
 
1315
                IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
 
1316
                return;
 
1317
            }
 
1318
            IUResetSwitch(&TrackModeSP);
 
1319
            TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
 
1320
            TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
 
1321
            TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
 
1322
            TrackModeSP.sp[3].s= ISS_ON ;  /* zero */
 
1323
            
 
1324
            TrackModeSP.s = IPS_ALERT;
 
1325
            IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm OFF: approaching a critical situation, avoided by apmount, stopped motors, no tracking!", MasterAlarmODT[0].text);   
 
1326
        }
 
1327
        else if( MasterAlarmS[2].s == ISS_ON) /* a critical situation */
 
1328
        {
 
1329
 
 
1330
/* If Master Alarm is on it is "too" late. So we do the same as under MasterAlarmS[1].s == ISS_ON*/
 
1331
/* The device setting up the Master Alarm should switch power off*/
 
1332
            // ToDo
 
1333
            abortSlew(fd);
 
1334
            AbortSlewSP.s = IPS_OK;
 
1335
            IDSetSwitch(&AbortSlewSP, NULL);
 
1336
 
 
1337
 
 
1338
            if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
 
1339
            {
 
1340
                IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
 
1341
                return;
 
1342
            }
 
1343
            IUResetSwitch(&TrackModeSP);
 
1344
            TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
 
1345
            TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
 
1346
            TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
 
1347
            TrackModeSP.sp[3].s= ISS_ON  ;  /* zero */
 
1348
 
 
1349
            TrackModeSP.s = IPS_ALERT;
 
1350
            IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm ON: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
 
1351
        }
 
1352
        else if((MasterAlarmS[2].s == ISS_OFF) && (MasterAlarmS[1].s == ISS_OFF) && (MasterAlarmS[0].s == ISS_OFF))
 
1353
        {
 
1354
            //ToDo make the mastar alarm indicator more visible!!
 
1355
            TrackModeSP.s = IPS_OK;
 
1356
            IDSetSwitch(&TrackModeSP, "MasterAlarm Status ok");
 
1357
            // values obtained via ISPoll
 
1358
            IDSetNumber(&EquatorialCoordsWNP, "Setting (sending) EquatorialCoordsRNP on reset MasterAlarm");
 
1359
        }
 
1360
        else
 
1361
        {
 
1362
            if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
 
1363
            {
 
1364
                IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
 
1365
                return;
 
1366
            }
 
1367
            IUResetSwitch(&TrackModeSP);
 
1368
            TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
 
1369
            TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
 
1370
            TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
 
1371
            TrackModeSP.sp[3].s= ISS_ON  ;  /* zero */
 
1372
 
 
1373
            TrackModeSP.s = IPS_ALERT;
 
1374
            TrackModeSP.s = IPS_ALERT;
 
1375
            IDSetSwitch(&TrackModeSP, "Device %s MASTER ALARM Unknown Status", MasterAlarmODT[0].text);
 
1376
        }
 
1377
    }
 
1378
    else if (IUSnoopSwitch(root, &ConnectionDCSP) == 0)
 
1379
    {
 
1380
        if( ConnectionDCS[0].s != ISS_ON)
 
1381
        {
 
1382
            // ToDo
 
1383
            abortSlew(fd);
 
1384
            AbortSlewSP.s = IPS_OK;
 
1385
            IDSetSwitch(&AbortSlewSP, NULL);
 
1386
 
 
1387
 
 
1388
            if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
 
1389
            {
 
1390
                IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
 
1391
                return;
 
1392
            }
 
1393
            IUResetSwitch(&TrackModeSP);
 
1394
            TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
 
1395
            TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
 
1396
            TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
 
1397
            TrackModeSP.sp[3].s= ISS_ON ;  /* zero */
 
1398
 
 
1399
            TrackModeSP.s = IPS_ALERT;
 
1400
            IDSetSwitch(&TrackModeSP, "Driver %s disconnected: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
 
1401
        }
 
1402
    }
 
1403
    else if (IUSnoopSwitch(root, &ModeSP) == 0)
 
1404
    {
 
1405
        if( ModeS[1].s == ISS_ON) /* late dome control mode */
 
1406
        {
 
1407
            getLX200RA( fd, &currentRA); 
 
1408
            getLX200DEC(fd, &currentDEC);
 
1409
 
 
1410
            targetRA= currentRA ;
 
1411
            targetDEC= currentDEC ;
 
1412
            EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
 
1413
            IDSetNumber(&EquatorialCoordsWNP, "Setting (sending) EquatorialCoordsRNP on ModeS[1].s != ISS_ON");
 
1414
            // sleep for 100 mseconds
 
1415
            usleep(100000);
 
1416
            EquatorialCoordsWNP.s = IPS_OK; 
 
1417
            IDSetNumber(&EquatorialCoordsWNP, NULL) ;
 
1418
        }
 
1419
    }
 
1420
}
 
1421
bool LX200AstroPhysics::isMountInit(void)
 
1422
{
 
1423
    return (StartUpSP.s != IPS_IDLE);
 
1424
}
 
1425
 
 
1426
void LX200AstroPhysics::ISPoll()
 
1427
{
 
1428
     int ret ;
 
1429
//     int ddd, mm ;
 
1430
     if (!isMountInit())
 
1431
         return;
 
1432
//     #ifdef INDI_DEBUG
 
1433
//     getSiteLongitude(fd, &ddd, &mm) ;
 
1434
//     IDLog("longitude %d:%d\n", ddd, mm);
 
1435
//     getSiteLatitude(fd, &ddd, &mm) ;
 
1436
//     IDLog("latitude %d:%d\n", ddd, mm);
 
1437
//     getAPUTCOffset( fd, &APUTCOffsetN[0].value) ;
 
1438
//     IDLog("UTC offset %10.6f\n", APUTCOffsetN[0].value);
 
1439
//     #endif
 
1440
 
 
1441
 
 
1442
     //============================================================
 
1443
     // #1 Call LX200Generic ISPoll
 
1444
     //============================================================
 
1445
     LX200Generic::ISPoll();
 
1446
 
 
1447
 
 
1448
     //============================================================
 
1449
     // #2 Get Local Time
 
1450
     //============================================================
 
1451
     if(( ret= getLocalTime24( fd, &APLocalTimeN[0].value)) == 0)
 
1452
     {
 
1453
         APLocalTimeNP.s = IPS_OK ;
 
1454
     }
 
1455
     else
 
1456
     {
 
1457
         APLocalTimeNP.s = IPS_ALERT ;
 
1458
     }
 
1459
     IDSetNumber(&APLocalTimeNP, NULL);
 
1460
 
 
1461
//     #ifdef INDI_DEBUG
 
1462
//     IDLog("localtime %f\n", APLocalTimeN[0].value) ;
 
1463
//     #endif
 
1464
 
 
1465
     //============================================================
 
1466
     // #3 Get Sidereal Time
 
1467
     //============================================================
 
1468
     if(( ret= getSDTime( fd, &APSiderealTimeN[0].value)) == 0)
 
1469
     {
 
1470
         APSiderealTimeNP.s = IPS_OK ;
 
1471
     }
 
1472
     else
 
1473
     {
 
1474
         APSiderealTimeNP.s = IPS_ALERT ;
 
1475
     }
 
1476
     IDSetNumber(&APSiderealTimeNP, NULL);
 
1477
//     #ifdef INDI_DEBUG
 
1478
//     IDLog("siderealtime %f\n", APSiderealTimeN[0].value) ;
 
1479
//     #endif
 
1480
 
 
1481
     //============================================================
 
1482
     // #4 Get UTC Offset
 
1483
     //============================================================
 
1484
     if(( ret= getAPUTCOffset( fd, &APUTCOffsetN[0].value)) == 0)
 
1485
     {
 
1486
         APUTCOffsetNP.s = IPS_OK ;
 
1487
     }
 
1488
     else
 
1489
     {
 
1490
         APUTCOffsetNP.s = IPS_ALERT ;
 
1491
     }
 
1492
     IDSetNumber(&APUTCOffsetNP, NULL);
 
1493
 
 
1494
     //============================================================
 
1495
     // #5 
 
1496
     //============================================================
 
1497
     if(( ret= getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) == 0)
 
1498
     {
 
1499
         DeclinationAxisTP.s = IPS_OK ;
 
1500
     }
 
1501
     else
 
1502
 
 
1503
     {
 
1504
         DeclinationAxisTP.s = IPS_ALERT ;
 
1505
     }
 
1506
     IDSetText(&DeclinationAxisTP, NULL) ;
 
1507
 
 
1508
 
 
1509
     /* LX200Generic should take care of this */
 
1510
     //getLX200RA(fd, &currentRA );
 
1511
     //getLX200DEC(fd, &currentDEC );
 
1512
     //EquatorialCoordsRNP.s = IPS_OK ;
 
1513
     //IDSetNumber (&EquatorialCoordsRNP, NULL);
 
1514
     
 
1515
   
 
1516
/* Calculate the hour angle */
 
1517
 
 
1518
     HourangleCoordsNP.np[0].value= 180. /M_PI/15. * LDRAtoHA( 15.* currentRA /180. *M_PI, -geoNP.np[1].value/180. *M_PI);
 
1519
     HourangleCoordsNP.np[1].value= currentDEC;
 
1520
 
 
1521
     HourangleCoordsNP.s = IPS_OK;
 
1522
     IDSetNumber(&HourangleCoordsNP, NULL);
 
1523
 
 
1524
     getLX200Az(fd, &currentAZ);
 
1525
     getLX200Alt(fd, &currentALT);
 
1526
 
 
1527
     /* The state of RNP is coupled to the WNP 
 
1528
     HorizontalCoordsRNP.s = IPS_OK ;
 
1529
     IDSetNumber (&HorizontalCoordsRNP, NULL);
 
1530
     */
 
1531
 
 
1532
     // LX200generic has no  HorizontalCoords(R|W)NP
 
1533
     if( HorizontalCoordsWNP.s == IPS_BUSY) /* telescope is syncing or slewing */
 
1534
     {
 
1535
         
 
1536
         double dx = fabs ( targetAZ  - currentAZ);
 
1537
         double dy = fabs ( targetALT  - currentALT);
 
1538
 
 
1539
         if (dx <= (SlewAccuracyNP.np[0].value/(60.0*15.0)) && (dy <= SlewAccuracyNP.np[1].value/60.0)) 
 
1540
         {
 
1541
             #ifdef INDI_DEBUG
 
1542
             IDLog("Slew completed.\n");
 
1543
             #endif
 
1544
             HorizontalCoordsWNP.s = IPS_OK ;
 
1545
             IDSetNumber(&HorizontalCoordsWNP, "Slew completed") ;
 
1546
         }
 
1547
         else
 
1548
         {
 
1549
             #ifdef INDI_DEBUG
 
1550
             IDLog("Slew in progress.\n");
 
1551
             #endif
 
1552
         }
 
1553
     }
 
1554
     if(StartUpSP.s== IPS_OK) /* the dome controller needs to be informed even in case dc has been started long after lx200ap*/
 
1555
     {
 
1556
         StartUpSP.s = IPS_OK ;
 
1557
         IDSetSwitch(&StartUpSP, NULL) ;
 
1558
     }
 
1559
     else
 
1560
     {
 
1561
         StartUpSP.s = IPS_ALERT ;
 
1562
         IDSetSwitch(&StartUpSP, NULL) ;
 
1563
     }
 
1564
 
 
1565
}
 
1566
int LX200AstroPhysics::setBasicDataPart0()
 
1567
{
 
1568
    int err ;
 
1569
#ifdef HAVE_NOVA_H
 
1570
    struct ln_date utm;
 
1571
    struct ln_zonedate ltm;
 
1572
#endif
 
1573
    if(setAPClearBuffer( fd) < 0)
 
1574
    {
 
1575
        handleError(&ConnectSP, err, "Clearing the buffer");
 
1576
        return -1;
 
1577
    }
 
1578
    if(setAPLongFormat( fd) < 0)
 
1579
    {
 
1580
        IDMessage( myapdev, "Setting long format failed") ;
 
1581
        return -1;
 
1582
    }
 
1583
    
 
1584
    // ToDo make a property
 
1585
    if(setAPBackLashCompensation(fd, 0,0,0) < 0)
 
1586
    {
 
1587
        handleError(&ConnectSP, err, "Setting back lash compensation");
 
1588
        return -1;
 
1589
    }
 
1590
#if defined HAVE_NOVA_H
 
1591
    ln_get_date_from_sys( &utm) ;
 
1592
    ln_date_to_zonedate(&utm, &ltm, 3600);
 
1593
 
 
1594
    if((  err = setLocalTime(fd, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0))
 
1595
    {
 
1596
        handleError(&ConnectSP, err, "Setting local time");
 
1597
        return -1;
 
1598
    }
 
1599
    if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
 
1600
    {
 
1601
        handleError(&ConnectSP, err, "Setting local date");
 
1602
        return -1;
 
1603
    }
 
1604
    #ifdef INDI_DEBUG
 
1605
    IDLog("UT time is: %04d/%02d/%02d T %02d:%02d:%02d\n", utm.years, utm.months, utm.days, utm.hours, utm.minutes, (int)utm.seconds);
 
1606
    IDLog("Local time is: %04d/%02d/%02d T %02d:%02d:%02d\n", ltm.years, ltm.months, ltm.days, ltm.hours, ltm.minutes, (int)ltm.seconds);
 
1607
    #endif
 
1608
 
 
1609
    // ToDo: strange but true offset 22:56:07, -1:03:53 (valid for obs Vermes)
 
1610
    // Understand what happens with AP controller sidereal time, azimut coordinates
 
1611
    if((err = setAPUTCOffset( fd, -1.0647222)) < 0)
 
1612
    {
 
1613
        handleError(&ConnectSP, err,"Setting AP UTC offset") ;
 
1614
        return -1;
 
1615
    }
 
1616
#else
 
1617
    IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
 
1618
#endif
 
1619
 
 
1620
    return 0 ;
 
1621
}
 
1622
int LX200AstroPhysics::setBasicDataPart1()
 
1623
{
 
1624
    int err ;
 
1625
 
 
1626
    if((err = setAPUnPark( fd)) < 0)
 
1627
    {
 
1628
        handleError(&ConnectSP, err,"Unparking failed") ;
 
1629
        return -1;
 
1630
    }
 
1631
#ifdef INDI_DEBUG
 
1632
    IDLog("Unparking successful\n");
 
1633
#endif
 
1634
 
 
1635
    if((err = setAPMotionStop( fd)) < 0)
 
1636
    {
 
1637
        handleError(&ConnectSP, err, "Stop motion (:Q#) failed, check the mount") ;
 
1638
        return -1;
 
1639
    }
 
1640
#ifdef INDI_DEBUG
 
1641
    IDLog("Stopped any motion (:Q#)\n");
 
1642
#endif
 
1643
 
 
1644
    return 0 ;
 
1645
}
 
1646
void LX200AstroPhysics::connectTelescope()
 
1647
{
 
1648
    static int established= NOTESTABLISHED ;
 
1649
 
 
1650
    switch (ConnectSP.sp[0].s)
 
1651
    {
 
1652
        case ISS_ON:  
 
1653
        
 
1654
            if( ! established)
 
1655
            {
 
1656
                if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
 
1657
                {
 
1658
                    ConnectSP.sp[0].s = ISS_OFF;
 
1659
                    ConnectSP.sp[1].s = ISS_ON;
 
1660
                    IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text);
 
1661
                    established= NOTESTABLISHED ;
 
1662
                    return;
 
1663
                }
 
1664
                if (check_lx200ap_connection(fd))
 
1665
                {   
 
1666
                    ConnectSP.sp[0].s = ISS_OFF;
 
1667
                    ConnectSP.sp[1].s = ISS_ON;
 
1668
                    IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
 
1669
                    established= NOTESTABLISHED ;
 
1670
                    return;
 
1671
                }
 
1672
                established= ESTABLISHED ;
 
1673
                #ifdef INDI_DEBUG
 
1674
                IDLog("Telescope test successful\n");
 
1675
                #endif
 
1676
                // At this point e.g. no GEOGRAPHIC_COORD are available after the first client connects.
 
1677
                // Postpone set up of the telescope
 
1678
                // NO setBasicData() ;
 
1679
 
 
1680
                // ToDo what is that *((int *) UTCOffsetN[0].aux0) = 0;
 
1681
                // Jasem: This is just a way to know if the client has init UTC Offset, and if he did, then we set aux0 to 1, otherwise it stays at 0. When
 
1682
                // the client tries to change UTC, but has not set UTFOffset yet (that is, aux0 = 0) then we can tell him to set the UTCOffset first. Btw,
 
1683
                // the UTF & UTFOffset will be merged in one property for INDI v0.6
 
1684
                ConnectSP.s = IPS_OK;
 
1685
                IDSetSwitch (&ConnectSP, "Telescope is online");
 
1686
            }
 
1687
            else
 
1688
            {
 
1689
                ConnectSP.s = IPS_OK;
 
1690
                IDSetSwitch (&ConnectSP, "Connection already established.");
 
1691
            }
 
1692
            break;
 
1693
 
 
1694
        case ISS_OFF:
 
1695
            ConnectSP.sp[0].s = ISS_OFF;
 
1696
            ConnectSP.sp[1].s = ISS_ON;
 
1697
            ConnectSP.s = IPS_IDLE;
 
1698
            IDSetSwitch (&ConnectSP, "Telescope is offline.");
 
1699
            if (setAPPark(fd) < 0)
 
1700
            {
 
1701
                ParkSP.s = IPS_ALERT;
 
1702
                IDSetSwitch(&ParkSP, "Parking Failed.");
 
1703
            return;
 
1704
            }
 
1705
 
 
1706
            ParkSP.s = IPS_OK;
 
1707
            IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting...");
 
1708
 
 
1709
            tty_disconnect(fd);
 
1710
            established= NOTESTABLISHED ;
 
1711
#ifdef INDI_DEBUG
 
1712
            IDLog("The telescope is parked. Turn off the telescope. Disconnected.\n");
 
1713
#endif
 
1714
            break;
 
1715
    }
 
1716
}
 
1717
// taken from lx200_16
 
1718
void LX200AstroPhysics::handleAltAzSlew()
 
1719
{
 
1720
    int i=0;
 
1721
    char altStr[64], azStr[64];
 
1722
 
 
1723
    if (HorizontalCoordsWNP.s == IPS_BUSY)
 
1724
    {
 
1725
        abortSlew(fd);
 
1726
        AbortSlewSP.s = IPS_OK;
 
1727
        IDSetSwitch(&AbortSlewSP, NULL);
 
1728
 
 
1729
        // sleep for 100 mseconds
 
1730
        usleep(100000);
 
1731
    }
 
1732
// ToDo is it ok ?
 
1733
//    if ((i = slewToAltAz(fd)))
 
1734
    if ((i = Slew(fd)))
 
1735
    {
 
1736
        HorizontalCoordsWNP.s = IPS_ALERT;
 
1737
        IDSetNumber(&HorizontalCoordsWNP, "Slew is not possible.");
 
1738
        return;
 
1739
    }
 
1740
 
 
1741
    HorizontalCoordsWNP.s = IPS_OK;
 
1742
    fs_sexa(azStr, targetAZ, 2, 3600);
 
1743
    fs_sexa(altStr, targetALT, 2, 3600);
 
1744
 
 
1745
    IDSetNumber(&HorizontalCoordsWNP, "Slewing to Alt %s - Az %s", altStr, azStr);
 
1746
    return;
 
1747
}
 
1748
void LX200AstroPhysics::handleEqCoordSet()
 
1749
{
 
1750
    int sync ;
 
1751
    int  err;
 
1752
    char syncString[256];
 
1753
    char RAStr[32], DecStr[32];
 
1754
    double dx, dy;
 
1755
    int syncOK= 0 ;
 
1756
    double targetHA ;
 
1757
 
 
1758
#ifdef INDI_DEBUG
 
1759
    IDLog("In Handle AP EQ Coord Set(), switch %d\n", getOnSwitch(&OnCoordSetSP));
 
1760
#endif
 
1761
    switch (getOnSwitch(&OnCoordSetSP))
 
1762
    {
 
1763
        // Slew
 
1764
        case LX200_TRACK:
 
1765
            lastSet = LX200_TRACK;
 
1766
            if (EquatorialCoordsWNP.s == IPS_BUSY)
 
1767
            {
 
1768
#ifdef INDI_DEBUG
 
1769
                IDLog("Aborting Track\n");
 
1770
#endif
 
1771
                // ToDo
 
1772
                abortSlew(fd);
 
1773
                AbortSlewSP.s = IPS_OK;
 
1774
                IDSetSwitch(&AbortSlewSP, NULL);
 
1775
 
 
1776
                // sleep for 100 mseconds
 
1777
                usleep(100000);
 
1778
            }
 
1779
            if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
 
1780
            {
 
1781
                slewError(err);
 
1782
                // ToDo handle that with the handleError function
 
1783
                return ;
 
1784
            }
 
1785
            EquatorialCoordsWNP.s = IPS_BUSY;
 
1786
            fs_sexa(RAStr,  targetRA, 2, 3600);
 
1787
            fs_sexa(DecStr, targetDEC, 2, 3600);
 
1788
            IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
 
1789
#ifdef INDI_DEBUG
 
1790
            IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
 
1791
#endif
 
1792
            break;
 
1793
 
 
1794
 
 
1795
            // Sync
 
1796
        case LX200_SYNC:
 
1797
 
 
1798
            lastSet = LX200_SYNC;
 
1799
 
 
1800
/* Astro-Physics has two sync options. In order that no collision occurs, the SYNCCMR */
 
1801
/* variant behaves for now identical like SYNCCM. Later this feature will be enabled.*/ 
 
1802
/* Calculate the hour angle of the target */
 
1803
 
 
1804
            targetHA= 180. /M_PI/15. * LDRAtoHA( 15.*  targetRA/180. *M_PI, -geoNP.np[1].value/180. *M_PI);
 
1805
 
 
1806
            if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
 
1807
            {
 
1808
                if (!strcmp("West", DeclinationAxisT[0].text))
 
1809
                {
 
1810
                    if(( targetHA > 12.0) && ( targetHA <= 24.0))
 
1811
                    {
 
1812
                        syncOK= 1 ;
 
1813
                    }
 
1814
                    else
 
1815
                    {
 
1816
                        syncOK= 0 ;
 
1817
                    }
 
1818
                }
 
1819
                else if (!strcmp("East", DeclinationAxisT[0].text))
 
1820
                {
 
1821
                    if(( targetHA >= 0.0) && ( targetHA <= 12.0))
 
1822
                    {
 
1823
                        syncOK= 1 ;
 
1824
                    }
 
1825
                    else
 
1826
                    {
 
1827
                        syncOK= 0 ;
 
1828
                    }
 
1829
                }
 
1830
                else
 
1831
                {
 
1832
#ifdef INDI_DEBUG
 
1833
                    IDLog("handleEqCoordSet(): SYNC NOK not East or West\n") ;
 
1834
#endif
 
1835
                    return ;
 
1836
                }
 
1837
            }
 
1838
            else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
 
1839
            {
 
1840
                syncOK = 1 ;
 
1841
            }
 
1842
            else
 
1843
            {
 
1844
#ifdef INDI_DEBUG
 
1845
                IDLog("handleEqCoordSet(): SYNC NOK not SYNCCM or SYNCCMR\n") ;
 
1846
#endif
 
1847
                return ;
 
1848
            }
 
1849
            if( syncOK == 1)
 
1850
            {
 
1851
                if( (sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
 
1852
                {
 
1853
                    if ( ( err = APSyncCM(fd, syncString) < 0) )
 
1854
                    {
 
1855
                        EquatorialCoordsWNP.s = IPS_ALERT ;
 
1856
                        IDSetNumber( &EquatorialCoordsWNP , "Synchronization failed.");
 
1857
                        // ToDo handle with handleError function
 
1858
                        return ;
 
1859
                    }
 
1860
                }
 
1861
                else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
 
1862
                {
 
1863
                    if ( ( err = APSyncCMR(fd, syncString) < 0) )
 
1864
                    {
 
1865
                        EquatorialCoordsWNP.s = IPS_ALERT ;
 
1866
                        IDSetNumber( &EquatorialCoordsWNP, "Synchronization failed.");
 
1867
                        // ToDo handle with handleError function
 
1868
                        return ;
 
1869
                    }
 
1870
                }
 
1871
                else
 
1872
                {
 
1873
                    EquatorialCoordsWNP.s = IPS_ALERT ;
 
1874
                    IDSetNumber( &EquatorialCoordsWNP , "SYNC NOK no valid SYNCCM, SYNCCMR");
 
1875
#ifdef INDI_DEBUG
 
1876
                    IDLog("SYNC NOK no valid SYNCCM, SYNCCMR\n") ;
 
1877
#endif
 
1878
                    return ;
 
1879
                }
 
1880
/* get the property DeclinationAxisTP first */
 
1881
                if(( err = getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) < 0)
 
1882
                {
 
1883
                    //ToDo handleErr
 
1884
                    DeclinationAxisTP.s = IPS_ALERT ;
 
1885
                    IDSetText(&DeclinationAxisTP, "Declination axis undefined") ;  
 
1886
                    return ;
 
1887
                }
 
1888
 
 
1889
                DeclinationAxisTP.s = IPS_OK ;
 
1890
#ifdef INDI_DEBUG
 
1891
                IDLog("Declination axis is on the %s side\n", DeclinationAxisT[0].text) ;
 
1892
#endif
 
1893
                IDSetText(&DeclinationAxisTP, NULL) ; 
 
1894
 
 
1895
                getLX200RA( fd, &currentRA); 
 
1896
                getLX200DEC(fd, &currentDEC);
 
1897
// The mount executed the sync command, now read back the values, make a IDSet in order the dome controller
 
1898
// is aware of the new target
 
1899
                targetRA= currentRA ;
 
1900
                targetDEC= currentDEC ;
 
1901
                EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
 
1902
                IDSetNumber(&EquatorialCoordsWNP,  "EquatorialCoordsWNP.s = IPS_BUSY after SYNC");
 
1903
            }
 
1904
            else
 
1905
            {
 
1906
#ifdef INDI_DEBUG
 
1907
                IDLog("Synchronization not allowed\n") ;
 
1908
#endif
 
1909
 
 
1910
                EquatorialCoordsWNP.s = IPS_ALERT;
 
1911
                IDSetNumber(&EquatorialCoordsWNP,  "Synchronization not allowed" );
 
1912
 
 
1913
#ifdef INDI_DEBUG
 
1914
                    IDLog("Telescope is on the wrong side targetHA was %f\n", targetHA) ;
 
1915
#endif
 
1916
                DeclinationAxisTP.s = IPS_ALERT ;
 
1917
                IDSetText(&DeclinationAxisTP, "Telescope is on the wrong side targetHA was %f", targetHA) ;
 
1918
 
 
1919
                return ;
 
1920
            }
 
1921
#ifdef INDI_DEBUG
 
1922
            IDLog("Synchronization successful >%s<\n", syncString);
 
1923
#endif
 
1924
            EquatorialCoordsWNP.s = IPS_OK; /* see above for dome controller dc */
 
1925
            IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful, EquatorialCoordsWNP.s = IPS_OK after SYNC");
 
1926
            break;
 
1927
    }
 
1928
   return ;
 
1929
}
 
1930
 
 
1931
// ToDo Not yet used
 
1932
void LX200AstroPhysics::handleAZCoordSet()
 
1933
{
 
1934
    int  err;
 
1935
    char AZStr[32], AltStr[32];
 
1936
 
 
1937
    switch (getOnSwitch(&OnCoordSetSP))
 
1938
    {
 
1939
        // Slew
 
1940
        case LX200_TRACK:
 
1941
            lastSet = LX200_TRACK;
 
1942
            if (HorizontalCoordsWNP.s == IPS_BUSY)
 
1943
            {
 
1944
#ifdef INDI_DEBUG
 
1945
                IDLog("Aboring Slew\n");
 
1946
#endif
 
1947
                // ToDo
 
1948
                abortSlew(fd);
 
1949
                AbortSlewSP.s = IPS_OK;
 
1950
                IDSetSwitch(&AbortSlewSP, NULL);
 
1951
                // sleep for 100 mseconds
 
1952
                usleep(100000);
 
1953
            }
 
1954
 
 
1955
            if ((err = Slew(fd)))
 
1956
            {
 
1957
                slewError(err);
 
1958
                //ToDo handle it
 
1959
 
 
1960
                return ;
 
1961
            }
 
1962
 
 
1963
            HorizontalCoordsWNP.s = IPS_BUSY;
 
1964
            fs_sexa(AZStr, targetAZ, 2, 3600);
 
1965
            fs_sexa(AltStr, targetALT, 2, 3600);
 
1966
            IDSetNumber(&HorizontalCoordsWNP, "Slewing to AZ %s - Alt %s", AZStr, AltStr);
 
1967
#ifdef INDI_DEBUG
 
1968
            IDLog("Slewing to AZ %s - Alt %s\n", AZStr, AltStr);
 
1969
#endif
 
1970
            break;
 
1971
 
 
1972
            // Sync
 
1973
            /* ToDo DO SYNC */
 
1974
        case LX200_SYNC:
 
1975
            IDMessage( myapdev, "Sync not supported in ALT/AZ mode") ;
 
1976
 
 
1977
            break;
 
1978
    }
 
1979
}
 
1980
/*********Library Section**************/
 
1981
/*********Library Section**************/
 
1982
/*********Library Section**************/
 
1983
/*********Library Section**************/
 
1984
 
 
1985
double LDRAtoHA( double RA, double longitude)
 
1986
{
 
1987
#ifdef HAVE_NOVA_H
 
1988
    double HA ;
 
1989
    double JD ;
 
1990
    double theta_0= 0. ;
 
1991
    JD=  ln_get_julian_from_sys() ;
 
1992
 
 
1993
//    #ifdef INDI_DEBUG
 
1994
//    IDLog("LDRAtoHA: JD %f\n", JD);
 
1995
//    #endif
 
1996
 
 
1997
    theta_0= 15. * ln_get_mean_sidereal_time( JD) ;
 
1998
//    #ifdef INDI_DEBUG
 
1999
//    IDLog("LDRAtoHA:1 theta_0 %f\n", theta_0);
 
2000
//    #endif
 
2001
    theta_0= fmod( theta_0, 360.) ;
 
2002
 
 
2003
    theta_0=  theta_0 /180. * M_PI ;
 
2004
 
 
2005
    HA =  fmod(theta_0 - longitude - RA,  2. * M_PI) ;
 
2006
 
 
2007
    if( HA < 0.)
 
2008
    {
 
2009
        HA += 2. * M_PI ;
 
2010
    }
 
2011
    return HA ;
 
2012
#else
 
2013
    IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
 
2014
    return 0 ;
 
2015
#endif
 
2016
 
 
2017
 
2018
// Transformation from apparent to various coordinate systems 
 
2019
int LDAppToX( int trans_to, double *star_cat, double tjd, double *loc, double *hxt, double *star_trans)
 
2020
{
 
2021
#if defined HAVE_NOVASCC_H
 
2022
    short int error = 0;
 
2023
 
 
2024
/* 'deltat' is the difference in time scales, TT - UT1. */
 
2025
 
 
2026
    double deltat = 60.0;
 
2027
    double gst ;
 
2028
 
 
2029
/* Set x,y in case where sub arcsec precission is required */
 
2030
 
 
2031
    double x=0. ;
 
2032
    double y=0. ;
 
2033
    short int ref_option ;
 
2034
 
 
2035
 
 
2036
    double ra_ar, dec_ar;            /* apparent and refracted EQ coordinate system */
 
2037
    double az_ar, zd_ar ;    /* apparent and refracted, AltAz coordinate system */
 
2038
    double ra_art, dec_art ; /* apparent, refracted and telescope EQ coordinate system */
 
2039
 
 
2040
    double ha_ar ;
 
2041
    double ha_art ;
 
2042
 
 
2043
    cat_entry star   = {"FK5", "NONAME", 0, star_cat[0], star_cat[1], 0., 0., 0., 0.};
 
2044
 
 
2045
    site_info geo_loc= {loc[0], loc[1], loc[2], loc[3], loc[4]} ;
 
2046
 
 
2047
    /* A structure containing the body designation for Earth.*/
 
2048
 
 
2049
    body earth ;
 
2050
 
 
2051
    /* Set up the structure containing the body designation for Earth. */
 
2052
 
 
2053
    if ((error = set_body (0,3,"Earth", &earth)))
 
2054
    {
 
2055
        IDMessage( myapdev, "LDAppToX: Error %d from set_body.\n", error);
 
2056
        return -1;
 
2057
    }
 
2058
    switch (trans_to)
 
2059
    {
 
2060
        case ATA:  /* identity */
 
2061
 
 
2062
            star_trans[0]= star.ra ;
 
2063
            star_trans[1]= star.dec ;
 
2064
            break ;
 
2065
 
 
2066
        case ATR: /* T4, apparent to refracted */
 
2067
 
 
2068
/* Alt Azimut refraction */
 
2069
 
 
2070
            ref_option= 2 ;
 
2071
 
 
2072
/* Set x,y in case where sub arcsec precission is required */
 
2073
 
 
2074
            equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
 
2075
 
 
2076
            if(ra_ar <0.)
 
2077
            {
 
2078
                ra_ar += 24. ;
 
2079
            }
 
2080
 
 
2081
            star_trans[0]= ra_ar ;
 
2082
            star_trans[1]= dec_ar ;
 
2083
 
 
2084
            break ;
 
2085
 
 
2086
        case ARTT: /* T4, apparent, refracted to telescope */
 
2087
 
 
2088
/* Alt Azimut refraction */
 
2089
 
 
2090
            ref_option= 2 ;
 
2091
 
 
2092
/* Set x,y in case where sub arcsec precission is required */
 
2093
 
 
2094
            equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
 
2095
 
 
2096
/* Calculate the apparent refracted hour angle  */
 
2097
 
 
2098
            ha_ar= (gst + geo_loc.longitude/180. * 12. - ra_ar) ;
 
2099
 
 
2100
            if( ha_ar < 0.)
 
2101
            {
 
2102
                ha_ar += 24. ;
 
2103
            }
 
2104
/* Equatorial system of the telescope, these are ra_art,  dec_art needed for the setting */
 
2105
/* To be defined: sign of rotation   theta= -7.5 ; */
 
2106
/* The values of hxt are defined in the local hour system, ha [hour]*/
 
2107
 
 
2108
            if(( error= LDEqToEqT( ha_ar, dec_ar, hxt, &ha_art, &dec_art)) != 0)
 
2109
            {
 
2110
                IDMessage( myapdev, "LDAppToX: \nError in calculation\n\n");
 
2111
                return -1 ;
 
2112
            }
 
2113
            ra_art = -ha_art + gst  + geo_loc.longitude/180. * 12. ;
 
2114
 
 
2115
            if(ra_art <0.)
 
2116
            {
 
2117
                ra_art += 24. ;
 
2118
            }
 
2119
 
 
2120
            star_trans[0]= ra_art ;
 
2121
            star_trans[1]= dec_art ;
 
2122
 
 
2123
            break ;
 
2124
        case ARTTO: /* T5, apparent, refracted, telescope to observed*/
 
2125
            IDMessage( myapdev, "LDAppToX: Not yet implemented, exiting...\n") ;
 
2126
            return -1;
 
2127
            break ;
 
2128
        default:
 
2129
            IDMessage(myapdev, "LDAppToX: No default, exiting\n") ;
 
2130
            return -1;
 
2131
    }
 
2132
    return 0;
 
2133
#elif defined HAVE_NOVA_H
 
2134
    IDMessage( myapdev, "Only identity transformation is supported without HAVE_NOVASCC_H") ;
 
2135
    star_trans[0]= star_cat[0];
 
2136
    star_trans[1]= star_cat[1];
 
2137
    return 0 ;
 
2138
#else
 
2139
    IDMessage( myapdev, "Install libnova to use this feature") ; // we never get here
 
2140
    return 0 ;
 
2141
#endif
 
2142
}
 
2143
 
 
2144
// Trans form to the ideal telescope coordinate system (no mount defects)
 
2145
int LDEqToEqT( double ra_h, double dec_d, double *hxt, double *rat_h, double *dect_d)
 
2146
{
 
2147
    int res ;
 
2148
    int i,j;
 
2149
    double ra = ra_h / 12. * M_PI ; /* novas-c unit is hour */
 
2150
    double dec= dec_d/180. * M_PI ;
 
2151
 
 
2152
    double theta= hxt[0]/180. * M_PI ;
 
2153
    double gamma= hxt[1]/180. * M_PI ;
 
2154
 
 
2155
    double unit_vector_in[3]= {cos(dec)*cos(ra), cos(dec)*sin(ra), sin(dec)} ;
 
2156
    double unit_vector_rot[3]= {0.,0.,0.} ;
 
2157
    double unit_vector_tmp[3]= {0.,0.,0.} ;
 
2158
    double rat  ;
 
2159
    double dect  ;
 
2160
 
 
2161
    /* theta rotation around polar axis, gamma around y axis */
 
2162
    double rotation[3][3]=
 
2163
        {
 
2164
            {cos(gamma)*cos(theta),-(cos(gamma)*sin(theta)),-sin(gamma)},
 
2165
            {sin(theta),cos(theta),0},
 
2166
            {cos(theta)*sin(gamma),-(sin(gamma)*sin(theta)), cos(gamma)}
 
2167
        } ;
 
2168
 
 
2169
 
 
2170
    /* minus theta rotation around telescope polar axis */
 
2171
 
 
2172
    /* Despite the above matrix is correct, no body has a telescope */
 
2173
    /* with fixed setting circles in RA - or a telescope is usually */
 
2174
    /* calibrated in RA/HA by choosing one star. The matrix below */
 
2175
    /* takes that into account */
 
2176
 
 
2177
    double rotation_minus_theta[3][3]=
 
2178
            {
 
2179
                { cos(theta), sin(theta), 0.},
 
2180
                {-sin(theta), cos(theta), 0.},
 
2181
                {         0.,         0., 1.}
 
2182
            } ;
 
2183
 
 
2184
    unit_vector_in[0]= cos(dec)*cos(ra) ;
 
2185
    unit_vector_in[1]= cos(dec)*sin(ra) ;
 
2186
    unit_vector_in[2]= sin(dec) ;
 
2187
 
 
2188
    if( gamma < 0 )
 
2189
    {
 
2190
        IDMessage(myapdev, "LDEqToEqT: gamma is the distance from the celestial pole and always positive\n") ;
 
2191
        return -1 ;
 
2192
    }
 
2193
    for( i=0; i < 3 ; i++)
 
2194
    {
 
2195
        for( j=0; j < 3 ; j++)
 
2196
        {
 
2197
            unit_vector_tmp[i] += rotation[i][j] *  unit_vector_in[j] ;
 
2198
        }
 
2199
    }
 
2200
 
 
2201
    for( i=0; i < 3 ; i++)
 
2202
    {
 
2203
        for( j=0; j < 3 ; j++)
 
2204
        {
 
2205
            unit_vector_rot[i] += rotation_minus_theta[i][j] *  unit_vector_tmp[j] ;
 
2206
        }
 
2207
    }
 
2208
 
 
2209
    if(( res= LDCartToSph( unit_vector_rot, &rat, &dect))!= 0)
 
2210
    {
 
2211
        return -1 ;
 
2212
    }
 
2213
    else
 
2214
    {
 
2215
        *rat_h = rat /M_PI * 12. ;
 
2216
        *dect_d= dect/M_PI * 180. ;
 
2217
        return 0 ;
 
2218
    }
 
2219
}
 
2220
int LDCartToSph( double *vec, double *ra, double *dec)
 
2221
{
 
2222
 
 
2223
    if( vec[0] !=0.)
 
2224
    {
 
2225
        *ra = atan2( vec[1], vec[0]) ;
 
2226
    }
 
2227
    else
 
2228
    {
 
2229
        return -1 ;
 
2230
    }
 
2231
    *dec= asin( vec[2]) ;
 
2232
    return 0 ;
 
2233
}