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

Last change on this file since 689 was 490, checked in by campagne, 15 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.