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)
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.
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.
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
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/
30
#include "lx200driver.h"
31
#include "lx200apdriver.h"
32
#include "lx200aplib.h"
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"
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
65
#define CONTROL_GROUP "Control"
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 ;
82
static ISwitch DomeControlS[] =
84
{"ON" , "on" , ISS_ON, 0, 0},
85
{"OFF" , "off" , ISS_OFF, 0, 0},
88
ISwitchVectorProperty DomeControlSP =
90
myapdev, "DOMECONTROL" , "Dome control", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeControlS, NARRAY(DomeControlS), "", 0
93
static ISwitch StartUpS[] =
95
{"COLD" , "cold" , ISS_OFF, 0, 0},
96
{"WARM" , "warm" , ISS_ON, 0, 0},
99
ISwitchVectorProperty StartUpSP =
101
myapdev, "STARTUP" , "Mount init.", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, StartUpS, NARRAY(StartUpS), "", 0
105
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
106
static ISwitch ApparentToObservedS[] =
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},
114
ISwitchVectorProperty ApparentToObservedSP =
116
myapdev, "TRANSFORMATION" , "Transformation", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ApparentToObservedS, NARRAY(ApparentToObservedS), "", 0
120
static INumber HourangleCoordsN[] =
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},
125
static INumberVectorProperty HourangleCoordsNP =
127
myapdev, "HOURANGLE_COORD", "Hourangle Coords", BASIC_GROUP, IP_RO, 0., IPS_IDLE, HourangleCoordsN, NARRAY( HourangleCoordsN), "", 0
129
static INumber HorizontalCoordsRN[] =
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}
134
static INumberVectorProperty HorizontalCoordsRNP =
136
myapdev, "HORIZONTAL_COORD", "Horizontal Coords", BASIC_GROUP, IP_RO, 120, IPS_IDLE, HorizontalCoordsRN, NARRAY(HorizontalCoordsRN), "", 0
139
/* Horizontal Coordinates: Request Only */
140
static INumber HorizontalCoordsWN[] =
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}
145
static INumberVectorProperty HorizontalCoordsWNP =
147
myapdev, "HORIZONTAL_COORD_REQUEST", "Horizontal Coords", BASIC_GROUP, IP_WO, 120, IPS_IDLE, HorizontalCoordsWN, NARRAY(HorizontalCoordsWN), "", 0
149
/* Difference of the equatorial coordinates, used to estimate the applied corrections */
150
static INumber DiffEquatorialCoordsN[] =
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},
155
static INumberVectorProperty DiffEquatorialCoordsNP =
157
myapdev, "DIFFEQUATORIAL_COORD", "Diff. Eq.", BASIC_GROUP, IP_RO, 0., IPS_IDLE, DiffEquatorialCoordsN, NARRAY( DiffEquatorialCoordsN), "", 0
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},
166
ISwitchVectorProperty TrackModeSP =
168
myapdev, "TRACKINGMODE" , "Tracking mode", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0
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},
177
ISwitchVectorProperty MoveToRateSP =
179
myapdev, "MOVETORATE" , "Move to rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MoveToRateS, NARRAY(MoveToRateS), "", 0
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},
187
ISwitchVectorProperty SlewRateSP =
189
myapdev, "SLEWRATE" , "Slew rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewRateS, NARRAY(SlewRateS), "", 0
191
static ISwitch SwapS[] = {
192
{"NS" , "North/Sounth" , ISS_OFF, 0, 0},
193
{"EW" , "East/West" , ISS_OFF, 0, 0},
196
ISwitchVectorProperty SwapSP =
198
myapdev, "SWAP" , "Swap buttons", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SwapS, NARRAY(SwapS), "", 0
200
static ISwitch SyncCMRS[] = {
201
{":CM#" , ":CM#" , ISS_ON, 0, 0},
202
{":CMR#" , ":CMR#" , ISS_OFF, 0, 0},
205
ISwitchVectorProperty SyncCMRSP =
207
myapdev, "SYNCCMR" , "Sync", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SyncCMRS, NARRAY(SyncCMRS), "", 0
212
static IText VersionT[] =
214
// AP has only versionnumber
215
{ "Number", "", 0, 0, 0 ,0}
218
static ITextVectorProperty VersionInfo =
220
myapdev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0
225
static IText DeclinationAxisT[] =
227
{ "RELHA", "rel. to HA", 0, 0, 0, 0} ,
230
static ITextVectorProperty DeclinationAxisTP =
232
myapdev, "DECLINATIONAXIS", "Declination axis", MOUNT_GROUP, IP_RO, 0, IPS_IDLE, DeclinationAxisT, NARRAY(DeclinationAxisT), "" ,0
234
static INumber APLocalTimeN[] =
236
{"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0},
238
static INumberVectorProperty APLocalTimeNP =
240
myapdev, "APLOCALTIME", "AP local time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APLocalTimeN, NARRAY(APLocalTimeN), "", 0
242
static INumber APSiderealTimeN[] =
244
{"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0},
246
static INumberVectorProperty APSiderealTimeNP =
248
myapdev, "APSIDEREALTIME", "AP sidereal time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APSiderealTimeN, NARRAY(APSiderealTimeN), "", 0
251
static INumber APUTCOffsetN[] =
253
{"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0},
255
static INumberVectorProperty APUTCOffsetNP =
257
myapdev, "APUTCOFFSET", "AP UTC Offset", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, APUTCOffsetN, NARRAY(APUTCOffsetN), "", 0
260
static INumber HourAxisN[] =
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},
265
static INumberVectorProperty HourAxisNP =
267
myapdev, "HOURAXIS", "Hour axis", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, HourAxisN, NARRAY(HourAxisN), "", 0
271
static INumber AirN[] =
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},
277
static INumberVectorProperty AirNP =
279
myapdev, "ATMOSPHERE", "Atmosphere", ATMOSPHERE_GROUP, IP_RW, 0., IPS_IDLE, AirN, NARRAY(AirN), "", 0
283
static IText ConnectionDCODT[] =
285
{ "DEVICE", "Device", 0, 0, 0, 0} ,
286
{ "PROPERTY", "Property", 0, 0, 0, 0}
288
static ITextVectorProperty ConnectionDCODTP =
290
myapdev, "SNOOPCONNECTIONDC", "Snoop dc connection", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ConnectionDCODT, NARRAY(ConnectionDCODT), "" ,0
292
static IText MasterAlarmODT[]=
294
{ "DEVICE", "Device", 0, 0, 0, 0} ,
295
{ "PROPERTY", "Property", 0, 0, 0, 0}
297
static ITextVectorProperty MasterAlarmODTP =
299
myapdev, "SNOOPMASTERALARM", "Snoop dc master alarm", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, MasterAlarmODT, NARRAY(MasterAlarmODT), "" ,0
301
static IText ModeDCODT[] =
303
{ "DEVICE", "Device", 0, 0, 0, 0} ,
304
{ "PROPERTY", "Property", 0, 0, 0, 0}
306
static ITextVectorProperty ModeDCODTP =
308
myapdev, "SNOOPMODEDC", "Snoop dc mode", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ModeDCODT, NARRAY(ModeDCODT), "" ,0
310
/********************************************
311
Property: Park telescope to HOME
312
*********************************************/
314
static ISwitch ParkS[] =
316
{"PARK", "Park", ISS_OFF, 0, 0},
318
static ISwitchVectorProperty ParkSP =
320
myapdev, "TELESCOPE_PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0
323
/* SNOOPed properties */
325
static ISwitch ConnectionDCS[] =
327
{"CONNECT", "Connect", ISS_OFF, 0, 0},
328
{"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
331
static ISwitchVectorProperty ConnectionDCSP =
333
"dc", "CONNECTION", "Connection", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectionDCS, NARRAY(ConnectionDCS), "", 0
336
static ISwitch MasterAlarmS[] =
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},
344
static ISwitchVectorProperty MasterAlarmSP =
346
"dc", "MASTERALARM", "Master alarm", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MasterAlarmS, NARRAY(MasterAlarmS), "", 0
348
static ISwitch ModeS[] = {
349
{"MANUAL", "manual", ISS_ON, 0, 0},
350
{"DOMECONTROL", "dome control", ISS_OFF, 0, 0}
353
static ISwitchVectorProperty ModeSP = {
354
"dc", "MODE", "Mode", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ModeS, NARRAY(ModeS), "", 0
357
void changeLX200AstroPhysicsDeviceName(const char *newName)
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);
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);
392
LX200AstroPhysics::LX200AstroPhysics() : LX200Generic()
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);
404
IUSaveText(&PortTP.tp[0], dev);
405
IUSaveText(&DeclinationAxisTP.tp[0], status);
407
void LX200AstroPhysics::ISGetProperties (const char *dev)
409
if (dev && strcmp (thisDevice, dev))
412
LX200Generic::ISGetProperties(dev);
414
IDDelete(thisDevice, "TELESCOPE_PARK", NULL);
415
IDDefSwitch (&ParkSP, NULL);
416
IDDefText(&VersionInfo, NULL);
418
/* Communication group */
420
// AstroPhysics has no alignment mode
421
IDDelete(thisDevice, "Alignment", NULL);
422
IDDefSwitch (&StartUpSP, NULL);
423
IDDefSwitch (&DomeControlSP, NULL);
426
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
427
IDDefSwitch(&ApparentToObservedSP, NULL);
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);
442
IDDefText(&DeclinationAxisTP, NULL);
443
IDDefNumber(&APLocalTimeNP, NULL);
444
IDDefNumber(&APSiderealTimeNP, NULL);
445
IDDefNumber(&APUTCOffsetNP, NULL);
446
IDDefNumber(&HourAxisNP, NULL);
448
/* Atmosphere group */
450
IDDefNumber (&AirNP, NULL);
454
IDDefText (&ConnectionDCODTP, NULL);
455
IDDefText (&MasterAlarmODTP, NULL);
456
IDDefText (&ModeDCODTP, NULL);
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);
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 */
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);
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);
484
void LX200AstroPhysics::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
488
// ignore if not ours //
489
if (strcmp (dev, thisDevice))
492
// ===================================
493
// Snoop DC Connection
494
// ===================================
495
if (!strcmp(name, ConnectionDCODTP.name) )
497
tp = IUFindText( &ConnectionDCODTP, names[0] );
501
IUSaveText(tp, texts[0]);
502
tp = IUFindText( &ConnectionDCODTP, names[1] );
506
ConnectionDCODTP.s = IPS_OK;
507
IUSaveText(tp, texts[1]);
509
IDSnoopDevice( ConnectionDCODT[0].text, ConnectionDCODT[1].text);
511
ConnectionDCODTP.s= IPS_OK ;
512
IDSetText (&ConnectionDCODTP, "Snooping property %s at device %s", ConnectionDCODT[1].text, ConnectionDCODT[0].text);
516
// ===================================
518
// ===================================
519
if (!strcmp(name, MasterAlarmODTP.name) )
521
tp = IUFindText( &MasterAlarmODTP, names[0] );
525
IUSaveText(tp, texts[0]);
527
tp = IUFindText( &MasterAlarmODTP, names[1] );
530
IUSaveText(tp, texts[1]);
532
IDSnoopDevice( MasterAlarmODT[0].text, MasterAlarmODT[1].text);
534
MasterAlarmODTP.s= IPS_OK ;
535
IDSetText (&MasterAlarmODTP, "Snooping property %s at device %s", MasterAlarmODT[1].text, MasterAlarmODT[0].text) ;
539
// ===================================
541
// ===================================
542
if (!strcmp(name, ModeDCODTP.name) )
544
tp = IUFindText( &ModeDCODTP, names[0] );
548
IUSaveText(tp, texts[0]);
549
tp = IUFindText( &ModeDCODTP, names[1] );
553
ModeDCODTP.s = IPS_OK;
554
IUSaveText(tp, texts[1]);
556
IDSnoopDevice( ModeDCODT[0].text, ModeDCODT[1].text);
558
ModeDCODTP.s= IPS_OK ;
559
IDSetText (&ModeDCODTP, "Snooping property %s at device %s", ModeDCODT[1].text, ModeDCODT[0].text);
563
LX200Generic::ISNewText (dev, name, texts, names, n);
567
void LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
572
// ignore if not ours
573
if (strcmp (dev, thisDevice))
576
// ===================================
578
// ===================================
579
if (!strcmp (name, AirNP.name))
581
double newTemperature ;
584
if (checkPower(&AirNP))
587
for (nset = i = 0; i < n; i++)
589
np = IUFindNumber (&AirNP, names[i]);
592
newTemperature = values[i];
595
else if( np == &AirN[1])
597
newPressure = values[i];
600
else if( np == &AirN[2])
602
newHumidity = values[i];
610
AirN[0].value = newTemperature;
611
AirN[1].value = newPressure;
612
AirN[2].value = newHumidity;
614
IDSetNumber(&AirNP, NULL);
619
IDSetNumber(&AirNP, "Temperature, Pressure or Humidity missing or invalid");
624
// ===================================
626
// ===================================
627
if ( !strcmp (name, APUTCOffsetNP.name) )
630
if (checkPower(&APUTCOffsetNP))
633
if (values[0] <= 0.0 || values[0] > 24.0)
635
APUTCOffsetNP.s = IPS_IDLE;
636
IDSetNumber(&APUTCOffsetNP , "UTC offset invalid");
640
if(( ret = setAPUTCOffset(fd, values[0]) < 0) )
642
handleError(&APUTCOffsetNP, ret, "Setting AP UTC offset");
646
APUTCOffsetN[0].value = values[0];
647
APUTCOffsetNP.s = IPS_OK;
649
IDSetNumber(&APUTCOffsetNP, NULL);
654
// =======================================
655
// Hour axis' intersection with the sphere
656
// =======================================
657
if (!strcmp (name, HourAxisNP.name))
660
double newTheta, newGamma ;
662
if (checkPower(&HourAxisNP))
665
for (nset = i = 0; i < n; i++)
667
np = IUFindNumber (&HourAxisNP, names[i]);
668
if ( np == &HourAxisN[0])
670
newTheta = values[i];
671
nset += newTheta >= 0 && newTheta <= 360.0;
673
else if ( np == &HourAxisN[1])
675
newGamma = values[i];
676
nset += newGamma >= 0. && newGamma <= 90.0;
682
HourAxisNP.s = IPS_OK;
683
HourAxisN[0].value = newTheta;
684
HourAxisN[1].value = newGamma;
685
IDSetNumber(&HourAxisNP, NULL);
689
HourAxisNP.s = IPS_ALERT;
690
IDSetNumber(&HourAxisNP, "Theta or gamma missing or invalid");
696
// =======================================
697
// Equatorial Coord - SET
698
// =======================================
699
if (!strcmp (name, EquatorialCoordsWNP.name))
703
double newRA, newDEC ;
704
if (checkPower(&EquatorialCoordsWNP))
707
for (nset = i = 0; i < n; i++)
709
INumber *np = IUFindNumber (&EquatorialCoordsWNP, names[i]);
710
if (np == &EquatorialCoordsWNP.np[0])
713
nset += newRA >= 0 && newRA <= 24.0;
714
} else if (np == &EquatorialCoordsWNP.np[1])
717
nset += newDEC >= -90.0 && newDEC <= 90.0;
724
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
731
/*EquatorialCoordsWNP.s = IPS_BUSY;*/
732
char RAStr[32], DecStr[32];
734
fs_sexa(RAStr, newRA, 2, 3600);
735
fs_sexa(DecStr, newDEC, 2, 3600);
738
IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
739
IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
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 ;
753
hxt[0]= HourAxisN[0].value ;
754
hxt[1]= HourAxisN[1].value ;
756
if((ret = LDAppToX( getOnSwitch(&ApparentToObservedSP), eqn, ln_get_julian_from_sys(), geo, hxt, eqt)) != 0)
758
IDMessage( myapdev, "ISNewNumber: transformation %d failed", getOnSwitch(&ApparentToObservedSP)) ;
761
/*EquatorialCoordsWNP.s = IPS_BUSY;*/
768
if ( (ret = setAPObjectRA(fd, targetRA)) < 0 || ( ret = setAPObjectDEC(fd, targetDEC)) < 0)
770
DiffEquatorialCoordsNP.s= IPS_ALERT;
771
IDSetNumber(&DiffEquatorialCoordsNP, NULL);
772
handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC");
775
EquatorialCoordsWNP.s = IPS_OK;
776
IDSetNumber(&EquatorialCoordsWNP, NULL);
778
DiffEquatorialCoordsNP.np[0].value= targetRA - currentRA ;
779
DiffEquatorialCoordsNP.np[1].value= targetDEC - currentDEC;
780
DiffEquatorialCoordsNP.s= IPS_OK;
781
IDSetNumber(&DiffEquatorialCoordsNP, NULL);
783
// ToDo don't we need to stop the motion (:Q#)?
784
if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
786
IUResetSwitch(&MovementNSSP);
787
IUResetSwitch(&MovementWESP);
788
MovementNSSP.s = MovementWESP.s = IPS_IDLE;
789
IDSetSwitch(&MovementNSSP, NULL);
790
IDSetSwitch(&MovementWESP, NULL);
793
//ToDo : conversion to boolean {
794
// EquatorialCoordsWNP.s = IPS_ALERT;
795
// IDSetNumber(&EquatorialCoordsWNP, NULL);
801
EquatorialCoordsWNP.s = IPS_ALERT;
802
IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
807
// =======================================
808
// Horizontal Coords - SET
809
// =======================================
810
if ( !strcmp (name, HorizontalCoordsWNP.name) )
813
double newAz, newAlt ;
815
char altStr[64], azStr[64];
817
if (checkPower(&HorizontalCoordsWNP))
820
for (nset = i = 0; i < n; i++)
822
np = IUFindNumber (&HorizontalCoordsWNP, names[i]);
823
if (np == &HorizontalCoordsWN[0])
826
nset += newAz >= 0. && newAz <= 360.0;
828
else if (np == &HorizontalCoordsWN[1])
831
nset += newAlt >= -90. && newAlt <= 90.0;
836
if ( (ret = setAPObjectAZ(fd, newAz)) < 0 || (ret = setAPObjectAlt(fd, newAlt)) < 0)
838
handleError(&HorizontalCoordsWNP, ret, "Setting Alt/Az");
843
HorizontalCoordsWNP.s = IPS_OK;
844
IDSetNumber(&HorizontalCoordsWNP, NULL) ;
846
fs_sexa(azStr, targetAZ, 2, 3600);
847
fs_sexa(altStr, targetALT, 2, 3600);
849
//IDSetNumber (&HorizontalCoordsWNP, "Attempting to slew to Alt %s - Az %s", altStr, azStr);
854
HorizontalCoordsWNP.s = IPS_ALERT;
855
IDSetNumber(&HorizontalCoordsWNP, "Altitude or Azimuth missing or invalid");
861
// =======================================
862
// Geographical Location
863
// =======================================
864
if (!strcmp (name, geoNP.name))
866
// new geographic coords
867
double newLong = 0, newLat = 0;
871
if (checkPower(&geoNP))
874
for (nset = i = 0; i < n; i++)
876
np = IUFindNumber (&geoNP, names[i]);
877
if (np == &geoNP.np[0])
880
nset += newLat >= -90.0 && newLat <= 90.0;
881
} else if (np == &geoNP.np[1])
884
nset += newLong >= 0.0 && newLong < 360.0;
892
fs_sexa (l, newLat, 3, 3600);
893
fs_sexa (L, newLong, 4, 3600);
895
if ( ( err = setAPSiteLongitude(fd, 360.0 - newLong) < 0) )
897
handleError(&geoNP, err, "Setting site coordinates");
900
if ( ( err = setAPSiteLatitude(fd, newLat) < 0) )
902
handleError(&geoNP, err, "Setting site coordinates");
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);
913
strcpy(msg, "Lat or Long missing or invalid");
915
IDSetNumber (&geoNP, "%s", msg);
919
LX200Generic::ISNewNumber (dev, name, values, names, n);
922
void LX200AstroPhysics::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
926
// ignore if not ours //
927
if (strcmp (thisDevice, dev))
930
// =======================================
932
// =======================================
933
if (!strcmp (name, ConnectSP.name))
935
IUUpdateSwitch(&ConnectSP, states, names, n) ;
941
// ============================================================
942
// Satisfy AP mount initialization, see AP key pad manual p. 76
943
// ============================================================
944
if (!strcmp (name, StartUpSP.name))
948
static int mount_status= MOUNTNOTINITIALIZED ;
950
IUUpdateSwitch(&StartUpSP, states, names, n) ;
952
if( mount_status == MOUNTNOTINITIALIZED)
954
mount_status=MOUNTINITIALIZED;
956
if(( ret= setBasicDataPart0())< 0)
958
// ToDo do something if needed
959
StartUpSP.s = IPS_ALERT ;
960
IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
963
if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start)
965
if(( ret= setBasicDataPart1())< 0)
967
// ToDo do something if needed
968
StartUpSP.s = IPS_ALERT ;
969
IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
973
// Make sure that the mount is setup according to the properties
974
switch_nr = getOnSwitch(&TrackModeSP);
976
if ( ( err = selectAPTrackingMode(fd, switch_nr) < 0) )
978
handleError(&TrackModeSP, err, "StartUpSP: Setting tracking mode.");
981
TrackModeSP.s = IPS_OK;
982
IDSetSwitch(&TrackModeSP, NULL);
983
//ToDo set button swapping acording telescope east west
984
// ... some code here
986
switch_nr = getOnSwitch(&MoveToRateSP);
988
if ( ( err = selectAPMoveToRate(fd, switch_nr) < 0) )
990
handleError(&MoveToRateSP, err, "StartUpSP: Setting move to rate.");
993
MoveToRateSP.s = IPS_OK;
995
IDSetSwitch(&MoveToRateSP, NULL);
996
switch_nr = getOnSwitch(&SlewRateSP);
998
if ( ( err = selectAPSlewRate(fd, switch_nr) < 0) )
1000
handleError(&SlewRateSP, err, "StartUpSP: Setting slew rate.");
1003
SlewRateSP.s = IPS_OK;
1004
IDSetSwitch(&SlewRateSP, NULL);
1006
StartUpSP.s = IPS_OK ;
1007
IDSetSwitch(&StartUpSP, "Mount initialized") ;
1008
// Fetch the coordinates and set RNP and WNP
1009
getLX200RA( fd, ¤tRA);
1010
getLX200DEC(fd, ¤tDEC);
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");
1018
// sleep for 100 mseconds
1021
EquatorialCoordsWNP.s = IPS_OK;
1022
IDSetNumber(&EquatorialCoordsWNP, NULL);
1024
getLX200Az(fd, ¤tAZ);
1025
getLX200Alt(fd, ¤tALT);
1027
HorizontalCoordsRNP.s = IPS_OK ;
1028
IDSetNumber (&HorizontalCoordsRNP, NULL);
1030
VersionInfo.tp[0].text = new char[64];
1031
getAPVersionNumber(fd, VersionInfo.tp[0].text);
1033
VersionInfo.s = IPS_OK ;
1034
IDSetText(&VersionInfo, NULL);
1036
if(( getOnSwitch(&DomeControlSP))== DOMECONTROL)
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);
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);
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);
1052
// once chosen no unsnooping is possible
1053
DomeControlSP.s= IPS_OK ;
1054
IDSetSwitch(&DomeControlSP, NULL) ;
1058
IDMessage( myapdev, "Not operating in dome control mode") ;
1061
IDMessage( myapdev, "Libnova not compiled in, consider to install it (http://libnova.sourceforge.net/)") ;
1063
#ifndef HAVE_NOVASCC_H
1064
IDMessage( myapdev, "NOVASCC not compiled in, consider to install it (http://aa.usno.navy.mil/AA/)") ;
1069
StartUpSP.s = IPS_ALERT ;
1070
IDSetSwitch(&StartUpSP, "Mount is already initialized") ;
1075
// =======================================
1077
// =======================================
1078
if (!strcmp(name, ParkSP.name))
1080
if (checkPower(&ParkSP))
1083
if (EquatorialCoordsWNP.s == IPS_BUSY)
1085
// ToDo handle return value
1087
// sleep for 200 mseconds
1089
AbortSlewSP.s = IPS_OK;
1090
IDSetSwitch(&AbortSlewSP, NULL);
1094
if (setAPPark(fd) < 0)
1096
ParkSP.s = IPS_ALERT;
1097
IDSetSwitch(&ParkSP, "Parking Failed.");
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;
1109
IDSetSwitch(&ConnectSP, NULL);
1111
StartUpSP.s = IPS_IDLE ;
1112
IDSetSwitch(&StartUpSP, NULL) ;
1114
// ToDo reset all values
1119
// =======================================
1121
// =======================================
1122
if (!strcmp (name, TrackModeSP.name))
1124
if (checkPower(&TrackModeSP))
1127
IUResetSwitch(&TrackModeSP);
1128
IUUpdateSwitch(&TrackModeSP, states, names, n);
1129
trackingMode = getOnSwitch(&TrackModeSP);
1131
if ( ( err = selectAPTrackingMode(fd, trackingMode) < 0) )
1133
handleError(&TrackModeSP, err, "Setting tracking mode.");
1136
TrackModeSP.s = IPS_OK;
1137
IDSetSwitch(&TrackModeSP, NULL);
1138
if( trackingMode != 3) /* not zero */
1140
AbortSlewSP.s = IPS_IDLE;
1141
IDSetSwitch(&AbortSlewSP, NULL);
1146
// =======================================
1148
// =======================================
1149
if (!strcmp(name, SwapSP.name))
1153
if (checkPower(&SwapSP))
1156
IUResetSwitch(&SwapSP);
1157
IUUpdateSwitch(&SwapSP, states, names, n);
1158
currentSwap = getOnSwitch(&SwapSP);
1160
if(( err = swapAPButtons(fd, currentSwap) < 0) )
1162
handleError(&SwapSP, err, "Swapping buttons.");
1166
SwapS[0].s= ISS_OFF ;
1167
SwapS[1].s= ISS_OFF ;
1169
IDSetSwitch(&SwapSP, NULL);
1173
// =======================================
1175
// =======================================
1176
if (!strcmp (name, MoveToRateSP.name))
1180
if (checkPower(&MoveToRateSP))
1183
IUResetSwitch(&MoveToRateSP);
1184
IUUpdateSwitch(&MoveToRateSP, states, names, n);
1185
moveToRate = getOnSwitch(&MoveToRateSP);
1187
if ( ( err = selectAPMoveToRate(fd, moveToRate) < 0) )
1189
handleError(&MoveToRateSP, err, "Setting move to rate.");
1192
MoveToRateSP.s = IPS_OK;
1193
IDSetSwitch(&MoveToRateSP, NULL);
1197
// =======================================
1199
// =======================================
1200
if (!strcmp (name, SlewRateSP.name))
1204
if (checkPower(&SlewRateSP))
1207
IUResetSwitch(&SlewRateSP);
1208
IUUpdateSwitch(&SlewRateSP, states, names, n);
1209
slewRate = getOnSwitch(&SlewRateSP);
1211
if ( ( err = selectAPSlewRate(fd, slewRate) < 0) )
1213
handleError(&SlewRateSP, err, "Setting slew rate.");
1218
SlewRateSP.s = IPS_OK;
1219
IDSetSwitch(&SlewRateSP, NULL);
1223
// =======================================
1224
// Choose the appropriate sync command
1225
// =======================================
1226
if (!strcmp(name, SyncCMRSP.name))
1229
if (checkPower(&SyncCMRSP))
1232
IUResetSwitch(&SyncCMRSP);
1233
IUUpdateSwitch(&SyncCMRSP, states, names, n);
1234
currentSync = getOnSwitch(&SyncCMRSP);
1235
SyncCMRSP.s = IPS_OK;
1236
IDSetSwitch(&SyncCMRSP, NULL);
1240
#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
1241
// =======================================
1242
// Set various transformations
1243
// =======================================
1244
if (!strcmp (name, ApparentToObservedSP.name))
1247
if (checkPower(&ApparentToObservedSP))
1250
IUResetSwitch(&ApparentToObservedSP);
1251
IUUpdateSwitch(&ApparentToObservedSP, states, names, n);
1252
trans_to = getOnSwitch(&ApparentToObservedSP);
1254
ApparentToObservedSP.s = IPS_OK;
1255
IDSetSwitch(&ApparentToObservedSP, "Transformation %d", trans_to);
1259
if (!strcmp (name, DomeControlSP.name))
1261
if((DomeControlSP.s== IPS_OK) &&( DomeControlSP.sp[0].s== ISS_ON))
1264
IDLog("Once in dome control mode no return is possible (INDI has no \"unsnoop\")\n") ;
1266
DomeControlSP.s= IPS_ALERT ;
1267
IDSetSwitch(&DomeControlSP, "Once in dome control mode no return is possible (INDI has no \"unsnoop\")") ;
1271
int last_state= getOnSwitch(&DomeControlSP) ;
1272
IUResetSwitch(&DomeControlSP);
1273
IUUpdateSwitch(&DomeControlSP, states, names, n) ;
1274
DomeControlSP.s= IPS_OK ;
1275
IDSetSwitch(&DomeControlSP, NULL) ;
1277
if(( DomeControlSP.s== IPS_OK) &&( last_state== NOTDOMECONTROL)) /* dome control mode after mount init. */
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);
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);
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);
1297
LX200Generic::ISNewSwitch (dev, name, states, names, n);
1299
void LX200AstroPhysics::ISSnoopDevice (XMLEle *root)
1302
if (IUSnoopSwitch(root, &MasterAlarmSP) == 0)
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 */
1307
/* Stop if possible any motion */
1310
AbortSlewSP.s = IPS_OK;
1311
IDSetSwitch(&AbortSlewSP, NULL);
1313
if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
1315
IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
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 */
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);
1327
else if( MasterAlarmS[2].s == ISS_ON) /* a critical situation */
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*/
1334
AbortSlewSP.s = IPS_OK;
1335
IDSetSwitch(&AbortSlewSP, NULL);
1338
if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
1340
IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
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 */
1349
TrackModeSP.s = IPS_ALERT;
1350
IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm ON: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
1352
else if((MasterAlarmS[2].s == ISS_OFF) && (MasterAlarmS[1].s == ISS_OFF) && (MasterAlarmS[0].s == ISS_OFF))
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");
1362
if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
1364
IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
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 */
1373
TrackModeSP.s = IPS_ALERT;
1374
TrackModeSP.s = IPS_ALERT;
1375
IDSetSwitch(&TrackModeSP, "Device %s MASTER ALARM Unknown Status", MasterAlarmODT[0].text);
1378
else if (IUSnoopSwitch(root, &ConnectionDCSP) == 0)
1380
if( ConnectionDCS[0].s != ISS_ON)
1384
AbortSlewSP.s = IPS_OK;
1385
IDSetSwitch(&AbortSlewSP, NULL);
1388
if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
1390
IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
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 */
1399
TrackModeSP.s = IPS_ALERT;
1400
IDSetSwitch(&TrackModeSP, "Driver %s disconnected: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
1403
else if (IUSnoopSwitch(root, &ModeSP) == 0)
1405
if( ModeS[1].s == ISS_ON) /* late dome control mode */
1407
getLX200RA( fd, ¤tRA);
1408
getLX200DEC(fd, ¤tDEC);
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
1416
EquatorialCoordsWNP.s = IPS_OK;
1417
IDSetNumber(&EquatorialCoordsWNP, NULL) ;
1421
bool LX200AstroPhysics::isMountInit(void)
1423
return (StartUpSP.s != IPS_IDLE);
1426
void LX200AstroPhysics::ISPoll()
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);
1442
//============================================================
1443
// #1 Call LX200Generic ISPoll
1444
//============================================================
1445
LX200Generic::ISPoll();
1448
//============================================================
1449
// #2 Get Local Time
1450
//============================================================
1451
if(( ret= getLocalTime24( fd, &APLocalTimeN[0].value)) == 0)
1453
APLocalTimeNP.s = IPS_OK ;
1457
APLocalTimeNP.s = IPS_ALERT ;
1459
IDSetNumber(&APLocalTimeNP, NULL);
1461
// #ifdef INDI_DEBUG
1462
// IDLog("localtime %f\n", APLocalTimeN[0].value) ;
1465
//============================================================
1466
// #3 Get Sidereal Time
1467
//============================================================
1468
if(( ret= getSDTime( fd, &APSiderealTimeN[0].value)) == 0)
1470
APSiderealTimeNP.s = IPS_OK ;
1474
APSiderealTimeNP.s = IPS_ALERT ;
1476
IDSetNumber(&APSiderealTimeNP, NULL);
1477
// #ifdef INDI_DEBUG
1478
// IDLog("siderealtime %f\n", APSiderealTimeN[0].value) ;
1481
//============================================================
1482
// #4 Get UTC Offset
1483
//============================================================
1484
if(( ret= getAPUTCOffset( fd, &APUTCOffsetN[0].value)) == 0)
1486
APUTCOffsetNP.s = IPS_OK ;
1490
APUTCOffsetNP.s = IPS_ALERT ;
1492
IDSetNumber(&APUTCOffsetNP, NULL);
1494
//============================================================
1496
//============================================================
1497
if(( ret= getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) == 0)
1499
DeclinationAxisTP.s = IPS_OK ;
1504
DeclinationAxisTP.s = IPS_ALERT ;
1506
IDSetText(&DeclinationAxisTP, NULL) ;
1509
/* LX200Generic should take care of this */
1510
//getLX200RA(fd, ¤tRA );
1511
//getLX200DEC(fd, ¤tDEC );
1512
//EquatorialCoordsRNP.s = IPS_OK ;
1513
//IDSetNumber (&EquatorialCoordsRNP, NULL);
1516
/* Calculate the hour angle */
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;
1521
HourangleCoordsNP.s = IPS_OK;
1522
IDSetNumber(&HourangleCoordsNP, NULL);
1524
getLX200Az(fd, ¤tAZ);
1525
getLX200Alt(fd, ¤tALT);
1527
/* The state of RNP is coupled to the WNP
1528
HorizontalCoordsRNP.s = IPS_OK ;
1529
IDSetNumber (&HorizontalCoordsRNP, NULL);
1532
// LX200generic has no HorizontalCoords(R|W)NP
1533
if( HorizontalCoordsWNP.s == IPS_BUSY) /* telescope is syncing or slewing */
1536
double dx = fabs ( targetAZ - currentAZ);
1537
double dy = fabs ( targetALT - currentALT);
1539
if (dx <= (SlewAccuracyNP.np[0].value/(60.0*15.0)) && (dy <= SlewAccuracyNP.np[1].value/60.0))
1542
IDLog("Slew completed.\n");
1544
HorizontalCoordsWNP.s = IPS_OK ;
1545
IDSetNumber(&HorizontalCoordsWNP, "Slew completed") ;
1550
IDLog("Slew in progress.\n");
1554
if(StartUpSP.s== IPS_OK) /* the dome controller needs to be informed even in case dc has been started long after lx200ap*/
1556
StartUpSP.s = IPS_OK ;
1557
IDSetSwitch(&StartUpSP, NULL) ;
1561
StartUpSP.s = IPS_ALERT ;
1562
IDSetSwitch(&StartUpSP, NULL) ;
1566
int LX200AstroPhysics::setBasicDataPart0()
1571
struct ln_zonedate ltm;
1573
if(setAPClearBuffer( fd) < 0)
1575
handleError(&ConnectSP, err, "Clearing the buffer");
1578
if(setAPLongFormat( fd) < 0)
1580
IDMessage( myapdev, "Setting long format failed") ;
1584
// ToDo make a property
1585
if(setAPBackLashCompensation(fd, 0,0,0) < 0)
1587
handleError(&ConnectSP, err, "Setting back lash compensation");
1590
#if defined HAVE_NOVA_H
1591
ln_get_date_from_sys( &utm) ;
1592
ln_date_to_zonedate(&utm, <m, 3600);
1594
if(( err = setLocalTime(fd, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0))
1596
handleError(&ConnectSP, err, "Setting local time");
1599
if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
1601
handleError(&ConnectSP, err, "Setting local date");
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);
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)
1613
handleError(&ConnectSP, err,"Setting AP UTC offset") ;
1617
IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
1622
int LX200AstroPhysics::setBasicDataPart1()
1626
if((err = setAPUnPark( fd)) < 0)
1628
handleError(&ConnectSP, err,"Unparking failed") ;
1632
IDLog("Unparking successful\n");
1635
if((err = setAPMotionStop( fd)) < 0)
1637
handleError(&ConnectSP, err, "Stop motion (:Q#) failed, check the mount") ;
1641
IDLog("Stopped any motion (:Q#)\n");
1646
void LX200AstroPhysics::connectTelescope()
1648
static int established= NOTESTABLISHED ;
1650
switch (ConnectSP.sp[0].s)
1656
if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
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 ;
1664
if (check_lx200ap_connection(fd))
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 ;
1672
established= ESTABLISHED ;
1674
IDLog("Telescope test successful\n");
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() ;
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");
1689
ConnectSP.s = IPS_OK;
1690
IDSetSwitch (&ConnectSP, "Connection already established.");
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)
1701
ParkSP.s = IPS_ALERT;
1702
IDSetSwitch(&ParkSP, "Parking Failed.");
1707
IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting...");
1710
established= NOTESTABLISHED ;
1712
IDLog("The telescope is parked. Turn off the telescope. Disconnected.\n");
1717
// taken from lx200_16
1718
void LX200AstroPhysics::handleAltAzSlew()
1721
char altStr[64], azStr[64];
1723
if (HorizontalCoordsWNP.s == IPS_BUSY)
1726
AbortSlewSP.s = IPS_OK;
1727
IDSetSwitch(&AbortSlewSP, NULL);
1729
// sleep for 100 mseconds
1733
// if ((i = slewToAltAz(fd)))
1736
HorizontalCoordsWNP.s = IPS_ALERT;
1737
IDSetNumber(&HorizontalCoordsWNP, "Slew is not possible.");
1741
HorizontalCoordsWNP.s = IPS_OK;
1742
fs_sexa(azStr, targetAZ, 2, 3600);
1743
fs_sexa(altStr, targetALT, 2, 3600);
1745
IDSetNumber(&HorizontalCoordsWNP, "Slewing to Alt %s - Az %s", altStr, azStr);
1748
void LX200AstroPhysics::handleEqCoordSet()
1752
char syncString[256];
1753
char RAStr[32], DecStr[32];
1759
IDLog("In Handle AP EQ Coord Set(), switch %d\n", getOnSwitch(&OnCoordSetSP));
1761
switch (getOnSwitch(&OnCoordSetSP))
1765
lastSet = LX200_TRACK;
1766
if (EquatorialCoordsWNP.s == IPS_BUSY)
1769
IDLog("Aborting Track\n");
1773
AbortSlewSP.s = IPS_OK;
1774
IDSetSwitch(&AbortSlewSP, NULL);
1776
// sleep for 100 mseconds
1779
if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
1782
// ToDo handle that with the handleError function
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);
1790
IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
1798
lastSet = LX200_SYNC;
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 */
1804
targetHA= 180. /M_PI/15. * LDRAtoHA( 15.* targetRA/180. *M_PI, -geoNP.np[1].value/180. *M_PI);
1806
if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
1808
if (!strcmp("West", DeclinationAxisT[0].text))
1810
if(( targetHA > 12.0) && ( targetHA <= 24.0))
1819
else if (!strcmp("East", DeclinationAxisT[0].text))
1821
if(( targetHA >= 0.0) && ( targetHA <= 12.0))
1833
IDLog("handleEqCoordSet(): SYNC NOK not East or West\n") ;
1838
else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
1845
IDLog("handleEqCoordSet(): SYNC NOK not SYNCCM or SYNCCMR\n") ;
1851
if( (sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
1853
if ( ( err = APSyncCM(fd, syncString) < 0) )
1855
EquatorialCoordsWNP.s = IPS_ALERT ;
1856
IDSetNumber( &EquatorialCoordsWNP , "Synchronization failed.");
1857
// ToDo handle with handleError function
1861
else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
1863
if ( ( err = APSyncCMR(fd, syncString) < 0) )
1865
EquatorialCoordsWNP.s = IPS_ALERT ;
1866
IDSetNumber( &EquatorialCoordsWNP, "Synchronization failed.");
1867
// ToDo handle with handleError function
1873
EquatorialCoordsWNP.s = IPS_ALERT ;
1874
IDSetNumber( &EquatorialCoordsWNP , "SYNC NOK no valid SYNCCM, SYNCCMR");
1876
IDLog("SYNC NOK no valid SYNCCM, SYNCCMR\n") ;
1880
/* get the property DeclinationAxisTP first */
1881
if(( err = getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) < 0)
1884
DeclinationAxisTP.s = IPS_ALERT ;
1885
IDSetText(&DeclinationAxisTP, "Declination axis undefined") ;
1889
DeclinationAxisTP.s = IPS_OK ;
1891
IDLog("Declination axis is on the %s side\n", DeclinationAxisT[0].text) ;
1893
IDSetText(&DeclinationAxisTP, NULL) ;
1895
getLX200RA( fd, ¤tRA);
1896
getLX200DEC(fd, ¤tDEC);
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");
1907
IDLog("Synchronization not allowed\n") ;
1910
EquatorialCoordsWNP.s = IPS_ALERT;
1911
IDSetNumber(&EquatorialCoordsWNP, "Synchronization not allowed" );
1914
IDLog("Telescope is on the wrong side targetHA was %f\n", targetHA) ;
1916
DeclinationAxisTP.s = IPS_ALERT ;
1917
IDSetText(&DeclinationAxisTP, "Telescope is on the wrong side targetHA was %f", targetHA) ;
1922
IDLog("Synchronization successful >%s<\n", syncString);
1924
EquatorialCoordsWNP.s = IPS_OK; /* see above for dome controller dc */
1925
IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful, EquatorialCoordsWNP.s = IPS_OK after SYNC");
1931
// ToDo Not yet used
1932
void LX200AstroPhysics::handleAZCoordSet()
1935
char AZStr[32], AltStr[32];
1937
switch (getOnSwitch(&OnCoordSetSP))
1941
lastSet = LX200_TRACK;
1942
if (HorizontalCoordsWNP.s == IPS_BUSY)
1945
IDLog("Aboring Slew\n");
1949
AbortSlewSP.s = IPS_OK;
1950
IDSetSwitch(&AbortSlewSP, NULL);
1951
// sleep for 100 mseconds
1955
if ((err = Slew(fd)))
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);
1968
IDLog("Slewing to AZ %s - Alt %s\n", AZStr, AltStr);
1975
IDMessage( myapdev, "Sync not supported in ALT/AZ mode") ;
1980
/*********Library Section**************/
1981
/*********Library Section**************/
1982
/*********Library Section**************/
1983
/*********Library Section**************/
1985
double LDRAtoHA( double RA, double longitude)
1990
double theta_0= 0. ;
1991
JD= ln_get_julian_from_sys() ;
1993
// #ifdef INDI_DEBUG
1994
// IDLog("LDRAtoHA: JD %f\n", JD);
1997
theta_0= 15. * ln_get_mean_sidereal_time( JD) ;
1998
// #ifdef INDI_DEBUG
1999
// IDLog("LDRAtoHA:1 theta_0 %f\n", theta_0);
2001
theta_0= fmod( theta_0, 360.) ;
2003
theta_0= theta_0 /180. * M_PI ;
2005
HA = fmod(theta_0 - longitude - RA, 2. * M_PI) ;
2013
IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
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)
2021
#if defined HAVE_NOVASCC_H
2022
short int error = 0;
2024
/* 'deltat' is the difference in time scales, TT - UT1. */
2026
double deltat = 60.0;
2029
/* Set x,y in case where sub arcsec precission is required */
2033
short int ref_option ;
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 */
2043
cat_entry star = {"FK5", "NONAME", 0, star_cat[0], star_cat[1], 0., 0., 0., 0.};
2045
site_info geo_loc= {loc[0], loc[1], loc[2], loc[3], loc[4]} ;
2047
/* A structure containing the body designation for Earth.*/
2051
/* Set up the structure containing the body designation for Earth. */
2053
if ((error = set_body (0,3,"Earth", &earth)))
2055
IDMessage( myapdev, "LDAppToX: Error %d from set_body.\n", error);
2060
case ATA: /* identity */
2062
star_trans[0]= star.ra ;
2063
star_trans[1]= star.dec ;
2066
case ATR: /* T4, apparent to refracted */
2068
/* Alt Azimut refraction */
2072
/* Set x,y in case where sub arcsec precission is required */
2074
equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
2081
star_trans[0]= ra_ar ;
2082
star_trans[1]= dec_ar ;
2086
case ARTT: /* T4, apparent, refracted to telescope */
2088
/* Alt Azimut refraction */
2092
/* Set x,y in case where sub arcsec precission is required */
2094
equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
2096
/* Calculate the apparent refracted hour angle */
2098
ha_ar= (gst + geo_loc.longitude/180. * 12. - ra_ar) ;
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]*/
2108
if(( error= LDEqToEqT( ha_ar, dec_ar, hxt, &ha_art, &dec_art)) != 0)
2110
IDMessage( myapdev, "LDAppToX: \nError in calculation\n\n");
2113
ra_art = -ha_art + gst + geo_loc.longitude/180. * 12. ;
2120
star_trans[0]= ra_art ;
2121
star_trans[1]= dec_art ;
2124
case ARTTO: /* T5, apparent, refracted, telescope to observed*/
2125
IDMessage( myapdev, "LDAppToX: Not yet implemented, exiting...\n") ;
2129
IDMessage(myapdev, "LDAppToX: No default, exiting\n") ;
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];
2139
IDMessage( myapdev, "Install libnova to use this feature") ; // we never get here
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)
2149
double ra = ra_h / 12. * M_PI ; /* novas-c unit is hour */
2150
double dec= dec_d/180. * M_PI ;
2152
double theta= hxt[0]/180. * M_PI ;
2153
double gamma= hxt[1]/180. * M_PI ;
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.} ;
2161
/* theta rotation around polar axis, gamma around y axis */
2162
double rotation[3][3]=
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)}
2170
/* minus theta rotation around telescope polar axis */
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 */
2177
double rotation_minus_theta[3][3]=
2179
{ cos(theta), sin(theta), 0.},
2180
{-sin(theta), cos(theta), 0.},
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) ;
2190
IDMessage(myapdev, "LDEqToEqT: gamma is the distance from the celestial pole and always positive\n") ;
2193
for( i=0; i < 3 ; i++)
2195
for( j=0; j < 3 ; j++)
2197
unit_vector_tmp[i] += rotation[i][j] * unit_vector_in[j] ;
2201
for( i=0; i < 3 ; i++)
2203
for( j=0; j < 3 ; j++)
2205
unit_vector_rot[i] += rotation_minus_theta[i][j] * unit_vector_tmp[j] ;
2209
if(( res= LDCartToSph( unit_vector_rot, &rat, &dect))!= 0)
2215
*rat_h = rat /M_PI * 12. ;
2216
*dect_d= dect/M_PI * 180. ;
2220
int LDCartToSph( double *vec, double *ra, double *dec)
2225
*ra = atan2( vec[1], vec[0]) ;
2231
*dec= asin( vec[2]) ;