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

Last change on this file since 614 was 490, checked in by campagne, 14 years ago

import libindi (JEC)

File size: 62.6 KB
Line 
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 */
68extern INumberVectorProperty EquatorialCoordsWNP;
69extern INumberVectorProperty EquatorialCoordsRNP;
70extern ITextVectorProperty   PortTP ;
71extern ISwitchVectorProperty MovementNSSP ;
72extern ISwitchVectorProperty MovementWESP ;
73extern ISwitchVectorProperty ConnectSP ;
74extern ISwitchVectorProperty AbortSlewSP ;
75extern ISwitchVectorProperty OnCoordSetSP ;
76extern INumberVectorProperty geoNP ;
77extern INumberVectorProperty TrackingAccuracyNP ;
78extern INumberVectorProperty SlewAccuracyNP ;
79
80/* Communication */
81
82static ISwitch DomeControlS[] = 
83{
84    {"ON" , "on" , ISS_ON, 0, 0},
85    {"OFF" , "off" , ISS_OFF, 0, 0},
86};
87
88ISwitchVectorProperty DomeControlSP = 
89{ 
90    myapdev, "DOMECONTROL" , "Dome control", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeControlS, NARRAY(DomeControlS), "", 0
91};
92
93static ISwitch StartUpS[] = 
94{
95    {"COLD" , "cold" , ISS_OFF, 0, 0},
96    {"WARM" , "warm" , ISS_ON, 0, 0},
97};
98
99ISwitchVectorProperty 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
106static 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
114ISwitchVectorProperty ApparentToObservedSP = 
115{ 
116    myapdev, "TRANSFORMATION" , "Transformation", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ApparentToObservedS, NARRAY(ApparentToObservedS), "", 0
117};
118#endif
119
120static 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};
125static INumberVectorProperty  HourangleCoordsNP = 
126{
127    myapdev, "HOURANGLE_COORD", "Hourangle Coords", BASIC_GROUP, IP_RO, 0., IPS_IDLE, HourangleCoordsN, NARRAY( HourangleCoordsN), "", 0
128};
129static 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};
134static 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 */
140static 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};
145static 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 */
150static 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};
155static INumberVectorProperty  DiffEquatorialCoordsNP = 
156{
157    myapdev, "DIFFEQUATORIAL_COORD", "Diff. Eq.", BASIC_GROUP, IP_RO, 0., IPS_IDLE, DiffEquatorialCoordsN, NARRAY( DiffEquatorialCoordsN), "", 0
158};
159
160static 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};
166ISwitchVectorProperty TrackModeSP = 
167{ 
168    myapdev, "TRACKINGMODE" , "Tracking mode", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0
169};
170static 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
177ISwitchVectorProperty MoveToRateSP = 
178{ 
179    myapdev, "MOVETORATE" , "Move to rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MoveToRateS, NARRAY(MoveToRateS), "", 0
180};
181static 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
187ISwitchVectorProperty SlewRateSP = 
188{ 
189    myapdev, "SLEWRATE" , "Slew rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewRateS, NARRAY(SlewRateS), "", 0
190};
191static ISwitch SwapS[] = {
192    {"NS" , "North/Sounth" , ISS_OFF, 0, 0},
193    {"EW" , "East/West" , ISS_OFF, 0, 0},
194};
195
196ISwitchVectorProperty SwapSP = 
197{ 
198    myapdev, "SWAP" , "Swap buttons", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SwapS, NARRAY(SwapS), "", 0
199};
200static ISwitch SyncCMRS[] = {
201    {":CM#" , ":CM#" , ISS_ON, 0, 0},
202    {":CMR#" , ":CMR#" , ISS_OFF, 0, 0},
203};
204
205ISwitchVectorProperty 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
212static IText   VersionT[] =
213{
214// AP has only versionnumber
215    { "Number", "", 0, 0, 0 ,0}
216};
217
218static ITextVectorProperty VersionInfo = 
219{
220    myapdev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0
221};
222
223/* Mount */
224
225static IText   DeclinationAxisT[] =
226{
227    { "RELHA", "rel. to HA", 0, 0, 0, 0} ,
228};
229
230static ITextVectorProperty DeclinationAxisTP = 
231{
232    myapdev, "DECLINATIONAXIS", "Declination axis", MOUNT_GROUP, IP_RO, 0, IPS_IDLE, DeclinationAxisT, NARRAY(DeclinationAxisT), "" ,0
233};
234static INumber APLocalTimeN[] = 
235{
236    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
237};
238static INumberVectorProperty APLocalTimeNP = 
239{
240    myapdev, "APLOCALTIME", "AP local time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APLocalTimeN, NARRAY(APLocalTimeN), "", 0
241};
242static INumber APSiderealTimeN[] = 
243{
244    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
245};
246static INumberVectorProperty APSiderealTimeNP = 
247{
248    myapdev, "APSIDEREALTIME", "AP sidereal time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APSiderealTimeN, NARRAY(APSiderealTimeN), "", 0
249};
250
251static INumber APUTCOffsetN[] = 
252{
253    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
254};
255static INumberVectorProperty APUTCOffsetNP = 
256{
257    myapdev, "APUTCOFFSET", "AP UTC Offset", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, APUTCOffsetN, NARRAY(APUTCOffsetN), "", 0
258};
259
260static 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};
265static INumberVectorProperty HourAxisNP = 
266{
267    myapdev, "HOURAXIS", "Hour axis", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, HourAxisN, NARRAY(HourAxisN), "", 0
268};
269
270/* Atmosphere */
271static 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};
277static INumberVectorProperty AirNP = 
278{
279    myapdev, "ATMOSPHERE", "Atmosphere", ATMOSPHERE_GROUP, IP_RW, 0., IPS_IDLE, AirN, NARRAY(AirN), "", 0
280};
281
282/* Settings Group */
283static IText   ConnectionDCODT[] =
284{
285    { "DEVICE", "Device", 0, 0, 0, 0} ,
286    { "PROPERTY", "Property", 0, 0, 0, 0}
287};
288static ITextVectorProperty ConnectionDCODTP = 
289{
290    myapdev, "SNOOPCONNECTIONDC", "Snoop dc connection", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ConnectionDCODT, NARRAY(ConnectionDCODT), "" ,0
291};
292static IText MasterAlarmODT[]= 
293{
294    { "DEVICE", "Device", 0, 0, 0, 0} ,
295    { "PROPERTY", "Property", 0, 0, 0, 0}
296};
297static ITextVectorProperty MasterAlarmODTP = 
298{
299    myapdev, "SNOOPMASTERALARM", "Snoop dc master alarm", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, MasterAlarmODT, NARRAY(MasterAlarmODT), "" ,0
300};
301static IText   ModeDCODT[] =
302{
303    { "DEVICE", "Device", 0, 0, 0, 0} ,
304    { "PROPERTY", "Property", 0, 0, 0, 0}
305};
306static 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
314static ISwitch ParkS[] = 
315{ 
316    {"PARK", "Park", ISS_OFF, 0, 0}, 
317};
318static 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
325static ISwitch ConnectionDCS[] = 
326{ 
327  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
328  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
329};
330
331static ISwitchVectorProperty ConnectionDCSP = 
332{ 
333  "dc", "CONNECTION", "Connection", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectionDCS, NARRAY(ConnectionDCS), "", 0
334};     
335
336static 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
344static ISwitchVectorProperty MasterAlarmSP = 
345{ 
346  "dc", "MASTERALARM", "Master alarm", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MasterAlarmS, NARRAY(MasterAlarmS), "", 0
347};
348static ISwitch ModeS[] = { 
349  {"MANUAL", "manual", ISS_ON, 0, 0},                         
350  {"DOMECONTROL", "dome control", ISS_OFF, 0, 0}
351};
352
353static ISwitchVectorProperty ModeSP = { 
354  "dc", "MODE", "Mode", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ModeS, NARRAY(ModeS), "", 0
355};     
356
357void 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
392LX200AstroPhysics::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}
407void 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
484void 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
567void 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
922void 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 }
1299void 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}
1421bool LX200AstroPhysics::isMountInit(void)
1422{
1423    return (StartUpSP.s != IPS_IDLE);
1424}
1425
1426void 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}
1566int 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}
1622int 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}
1646void 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
1718void 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}
1748void 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
1932void 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
1985double 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
2019int 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)
2145int 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}
2220int 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}
Note: See TracBrowser for help on using the repository browser.