moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / indi / celestrongps.cpp
blobb4c9258e4d30df835e3fe7e703849bc8684fa278
1 #if 0
2 Celestron GPS
3 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #endif
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <math.h>
26 #include <unistd.h>
27 #include <time.h>
29 #include "celestronprotocol.h"
30 #include "celestrongps.h"
32 #define RA_THRESHOLD 0.01
33 #define DEC_THRESHOLD 0.05
34 #define mydev "Celestron GPS"
36 CelestronGPS *telescope = NULL;
39 /* There is _one_ binary for all LX200 drivers, but each binary is renamed
40 ** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
41 ** fetch from std args the binary name and ISInit will create the apporpiate
42 ** device afterwards. If the binary name does not match any known devices,
43 ** we simply create a generic device
45 extern char* me;
47 #define COMM_GROUP "Communication"
48 #define BASIC_GROUP "Main Control"
49 #define MOVE_GROUP "Movement Control"
51 static void ISPoll(void *);
53 /*INDI controls */
54 static ISwitch PowerS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
55 static ISwitch SlewModeS[] = {{"Slew", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0, 0}};
56 static ISwitch OnCoordSetS[] = {{"SLEW", "Slew", ISS_ON, 0 , 0}, {"TRACK", "Track", ISS_OFF, 0, 0}, {"SYNC", "Sync", ISS_OFF, 0, 0}};
57 static ISwitch abortSlewS[] = {{"ABORT", "Abort", ISS_OFF, 0, 0}};
59 static ISwitch MovementS[] = {{"N", "North", ISS_OFF, 0, 0}, {"W", "West", ISS_OFF, 0, 0}, {"E", "East", ISS_OFF, 0, 0}, {"S", "South", ISS_OFF, 0, 0}};
61 /* equatorial position */
62 static INumber eq[] = {
63 {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0},
64 {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
66 //TODO decide appropiate TIME_OUT
67 static INumberVectorProperty eqNum = {
68 mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE,
69 eq, NARRAY(eq), "", 0};
71 /* Fundamental group */
72 static ISwitchVectorProperty PowerSw = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
73 static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}};
74 static ITextVectorProperty Port = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
76 /* Movement group */
77 static ISwitchVectorProperty OnCoordSetSw = { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
78 static ISwitchVectorProperty abortSlewSw = { mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, abortSlewS, NARRAY(abortSlewS), "", 0};
79 static ISwitchVectorProperty SlewModeSw = { mydev, "Slew rate", "", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
81 static ISwitchVectorProperty MovementSw = { mydev, "MOVEMENT", "Move toward", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementS, NARRAY(MovementS), "", 0};
84 /* send client definitions of all properties */
85 void ISInit()
87 static int isInit=0;
89 if (isInit)
90 return;
92 isInit = 1;
94 PortT[0].text = strcpy(new char[32], "/dev/ttyS0");
96 telescope = new CelestronGPS();
98 IEAddTimer (POLLMS, ISPoll, NULL);
101 void ISGetProperties (const char *dev)
102 { ISInit(); telescope->ISGetProperties(dev);}
103 void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
104 { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
105 void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
106 { ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
107 void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
108 { ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
109 void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
110 void ISNewBLOB (const char */*dev*/, const char */*name*/, int */*sizes[]*/, char **/*blobs[]*/, char **/*formats[]*/, char **/*names[]*/, int /*n*/)
113 /**************************************************
114 *** LX200 Generic Implementation
115 ***************************************************/
117 CelestronGPS::CelestronGPS()
120 targetRA = lastRA = 0;
121 targetDEC = lastDEC = 0;
122 currentSet = 0;
123 lastSet = -1;
124 lastMove[0] = lastMove[1] = lastMove[2] = lastMove[3] = 0;
126 JD = 0;
128 // Children call parent routines, this is the default
129 IDLog("initilizaing from Celeston GPS device...\n");
133 void CelestronGPS::ISGetProperties(const char *dev)
136 if (dev && strcmp (mydev, dev))
137 return;
139 // COMM_GROUP
140 IDDefSwitch (&PowerSw, NULL);
141 IDDefText (&Port, NULL);
143 // BASIC_GROUP
144 IDDefNumber (&eqNum, NULL);
145 IDDefSwitch (&OnCoordSetSw, NULL);
146 IDDefSwitch (&abortSlewSw, NULL);
147 IDDefSwitch (&SlewModeSw, NULL);
149 // Movement group
150 IDDefSwitch (&MovementSw, NULL);
152 /* Send the basic data to the new client if the previous client(s) are already connected. */
153 if (PowerSw.s == IPS_OK)
154 getBasicData();
158 void CelestronGPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
160 IText *tp;
162 // suppress warning
163 n=n;
164 // ignore if not ours //
165 if (strcmp (dev, mydev))
166 return;
168 if (!strcmp(name, Port.name) )
170 Port.s = IPS_OK;
172 tp = IUFindText( &Port, names[0] );
173 if (!tp)
174 return;
176 tp->text = new char[strlen(texts[0])+1];
177 strcpy(tp->text, texts[0]);
178 IDSetText (&Port, NULL);
179 return;
183 int CelestronGPS::handleCoordSet()
186 int i=0;
187 char RAStr[32], DecStr[32];
189 switch (currentSet)
192 // Slew
193 case 0:
194 lastSet = 0;
195 if (eqNum.s == IPS_BUSY)
197 StopNSEW();
198 // sleep for 500 mseconds
199 usleep(500000);
202 if ((i = SlewToCoords(targetRA, targetDEC)))
204 slewError(i);
205 return (-1);
208 eqNum.s = IPS_BUSY;
209 fs_sexa(RAStr, targetRA, 2, 3600);
210 fs_sexa(DecStr, targetDEC, 2, 3600);
211 IDSetNumber(&eqNum, "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
212 IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
213 break;
216 // Track
217 case 1:
218 if (eqNum.s == IPS_BUSY)
220 StopNSEW();
221 // sleep for 500 mseconds
222 usleep(500000);
225 if ( (fabs ( targetRA - currentRA ) >= TRACKING_THRESHOLD) ||
226 (fabs (targetDEC - currentDEC) >= TRACKING_THRESHOLD))
229 IDLog("Exceeded Tracking threshold, will attempt to slew to the new target.\n");
230 IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
231 IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
233 if (( i = SlewToCoords(targetRA, targetDEC)))
235 slewError(i);
236 return (-1);
239 fs_sexa(RAStr, targetRA, 2, 3600);
240 fs_sexa(DecStr, targetDEC, 2, 3600);
241 eqNum.s = IPS_BUSY;
242 IDSetNumber(&eqNum, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
243 IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
245 else
247 IDLog("Tracking called, but tracking threshold not reached yet.\n");
248 eqNum.s = IPS_OK;
249 eqNum.np[0].value = currentRA;
250 eqNum.np[1].value = currentDEC;
251 if (lastSet != 1)
252 IDSetNumber(&eqNum, "Tracking...");
253 else
254 IDSetNumber(&eqNum, NULL);
256 lastSet = 1;
257 break;
259 // Sync
260 case 2:
261 lastSet = 2;
262 OnCoordSetSw.s = IPS_OK;
263 SyncToCoords(targetRA, targetDEC);
264 eqNum.s = IPS_OK;
265 IDSetNumber(&eqNum, "Synchronization successful.");
266 break;
269 return (0);
273 void CelestronGPS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
275 double newRA=0, newDEC=0;
277 // ignore if not ours //
278 if (strcmp (dev, mydev))
279 return;
281 struct tm *tp;
282 time_t t;
284 time (&t);
285 tp = gmtime (&t);
287 if (!strcmp (name, eqNum.name))
289 int i=0, nset=0;
291 if (checkPower(&eqNum))
292 return;
294 for (nset = i = 0; i < n; i++)
296 INumber *eqp = IUFindNumber (&eqNum, names[i]);
297 if (eqp == &eq[0])
299 newRA = values[i];
300 nset += newRA >= 0 && newRA <= 24.0;
301 } else if (eqp == &eq[1])
303 newDEC = values[i];
304 nset += newDEC >= -90.0 && newDEC <= 90.0;
308 if (nset == 2)
310 //eqNum.s = IPS_BUSY;
312 tp->tm_mon += 1;
313 tp->tm_year += 1900;
315 // update JD
316 JD = UTtoJD(tp);
318 IDLog("We recevined JNOW RA %f - DEC %f\n", newRA, newDEC);;
319 /*apparentCoord( (double) J2000, JD, &newRA, &newDEC);
320 IDLog("Processed to RA %f - DEC %f\n", newRA, newDEC);*/
322 //eqNum.np[0].value = values[0];
323 //eqNum.np[1].value = values[1];
324 targetRA = newRA;
325 targetDEC = newDEC;
327 if (MovementSw.s == IPS_BUSY)
329 for (int i=0; i < 4; i++)
331 lastMove[i] = 0;
332 MovementS[i].s = ISS_OFF;
335 MovementSw.s = IPS_IDLE;
336 IDSetSwitch(&MovementSw, NULL);
339 if (handleCoordSet())
341 eqNum.s = IPS_IDLE;
342 IDSetNumber(&eqNum, NULL);
345 else
347 eqNum.s = IPS_IDLE;
348 IDSetNumber(&eqNum, "RA or Dec missing or invalid.");
351 return;
355 void CelestronGPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
358 int index;
359 ISwitch *swp;
361 // Suppress warning
362 names = names;
364 //IDLog("in new Switch with Device= %s and Property= %s and #%d items\n", dev, name,n);
365 //IDLog("SolarSw name is %s\n", SolarSw.name);
367 // ignore if not ours //
368 if (strcmp (dev, mydev))
369 return;
371 // FIRST Switch ALWAYS for power
372 if (!strcmp (name, PowerSw.name))
374 IUResetSwitches(&PowerSw);
375 IUUpdateSwitches(&PowerSw, states, names, n);
376 powerTelescope();
377 return;
380 if (!strcmp(name, OnCoordSetSw.name))
382 if (checkPower(&OnCoordSetSw))
383 return;
385 IUResetSwitches(&OnCoordSetSw);
386 IUUpdateSwitches(&OnCoordSetSw, states, names, n);
387 currentSet = getOnSwitch(&OnCoordSetSw);
390 // Abort Slew
391 if (!strcmp (name, abortSlewSw.name))
393 if (checkPower(&abortSlewSw))
395 abortSlewSw.s = IPS_IDLE;
396 IDSetSwitch(&abortSlewSw, NULL);
397 return;
400 IUResetSwitches(&abortSlewSw);
401 StopNSEW();
403 if (eqNum.s == IPS_BUSY)
405 abortSlewSw.s = IPS_OK;
406 eqNum.s = IPS_IDLE;
407 IDSetSwitch(&abortSlewSw, "Slew aborted.");
408 IDSetNumber(&eqNum, NULL);
410 else if (MovementSw.s == IPS_BUSY)
413 for (int i=0; i < 4; i++)
414 lastMove[i] = 0;
416 MovementSw.s = IPS_IDLE;
417 abortSlewSw.s = IPS_OK;
418 eqNum.s = IPS_IDLE;
419 IUResetSwitches(&MovementSw);
420 IUResetSwitches(&abortSlewSw);
421 IDSetSwitch(&abortSlewSw, "Slew aborted.");
422 IDSetSwitch(&MovementSw, NULL);
423 IDSetNumber(&eqNum, NULL);
425 else
427 IUResetSwitches(&MovementSw);
428 abortSlewSw.s = IPS_IDLE;
429 IDSetSwitch(&abortSlewSw, NULL);
432 return;
435 // Slew mode
436 if (!strcmp (name, SlewModeSw.name))
438 if (checkPower(&SlewModeSw))
439 return;
441 IUResetSwitches(&SlewModeSw);
442 IUUpdateSwitches(&SlewModeSw, states, names, n);
443 index = getOnSwitch(&SlewModeSw);
444 SetRate(index);
446 SlewModeSw.s = IPS_OK;
447 IDSetSwitch(&SlewModeSw, NULL);
448 return;
451 // Movement
452 if (!strcmp (name, MovementSw.name))
454 if (checkPower(&MovementSw))
455 return;
457 index = -1;
458 IUUpdateSwitches(&MovementSw, states, names, n);
459 swp = IUFindSwitch(&MovementSw, names[0]);
461 if (!swp)
463 StopNSEW();
464 IUResetSwitches(&MovementSw);
465 MovementSw.s = IPS_IDLE;
466 IDSetSwitch(&MovementSw, NULL);
469 if (swp == &MovementS[0]) index = 0;
470 else if (swp == &MovementS[1]) index = 1;
471 else if (swp == &MovementS[2]) index = 2;
472 else index = 3;
474 lastMove[index] = lastMove[index] == 0 ? 1 : 0;
475 if (lastMove[index] == 0)
476 MovementS[index].s = ISS_OFF;
478 // North/South movement is illegal
479 if (lastMove[NORTH] && lastMove[SOUTH])
481 StopNSEW();
482 for (int i=0; i < 4; i++)
483 lastMove[i] = 0;
485 IUResetSwitches(&MovementSw);
486 MovementSw.s = IPS_IDLE;
487 IDSetSwitch(&MovementSw, "Slew aborted.");
488 return;
491 // East/West movement is illegal
492 if (lastMove[EAST] && lastMove[WEST])
494 StopNSEW();
495 for (int i=0; i < 4; i++)
496 lastMove[i] = 0;
498 IUResetSwitches(&MovementSw);
499 MovementSw.s = IPS_IDLE;
500 IDSetSwitch(&MovementSw, "Slew aborted.");
501 return;
504 //IDLog("We have switch %d \n ", index);
505 //IDLog("NORTH: %d -- WEST: %d -- EAST: %d -- SOUTH %d\n", lastMove[0], lastMove[1], lastMove[2], lastMove[3]);
507 if (lastMove[index] == 1)
508 StartSlew(index);
509 else
510 StopSlew(index);
512 if (!lastMove[0] && !lastMove[1] && !lastMove[2] && !lastMove[3])
513 MovementSw.s = IPS_IDLE;
515 if (lastMove[index] == 0)
516 IDSetSwitch(&MovementSw, "Moving toward %s aborted.", Direction[index]);
517 else
519 MovementSw.s = IPS_BUSY;
520 IDSetSwitch(&MovementSw, "Moving %s...", Direction[index]);
522 return;
528 int CelestronGPS::getOnSwitch(ISwitchVectorProperty *sp)
530 for (int i=0; i < sp->nsp ; i++)
531 if (sp->sp[i].s == ISS_ON)
532 return i;
534 return -1;
538 int CelestronGPS::checkPower(ISwitchVectorProperty *sp)
540 if (PowerSw.s != IPS_OK)
542 if (!strcmp(sp->label, ""))
543 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->name);
544 else
545 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->label);
547 sp->s = IPS_IDLE;
548 IDSetSwitch(sp, NULL);
549 return -1;
552 return 0;
555 int CelestronGPS::checkPower(INumberVectorProperty *np)
557 if (PowerSw.s != IPS_OK)
559 if (!strcmp(np->label, ""))
560 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->name);
561 else
562 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->label);
564 np->s = IPS_IDLE;
565 IDSetNumber(np, NULL);
566 return -1;
568 return 0;
571 int CelestronGPS::checkPower(ITextVectorProperty *tp)
574 if (PowerSw.s != IPS_OK)
576 if (!strcmp(tp->label, ""))
577 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->name);
578 else
579 IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->label);
581 tp->s = IPS_IDLE;
582 IDSetText(tp, NULL);
583 return -1;
586 return 0;
590 void CelestronGPS::ISPoll()
592 double dx, dy;
593 double currentRA, currentDEC;
594 int status;
596 switch (eqNum.s)
598 case IPS_IDLE:
599 if (PowerSw.s != IPS_OK)
600 break;
601 currentRA = GetRA();
602 currentDEC = GetDec();
604 if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
606 eqNum.np[0].value = currentRA;
607 eqNum.np[1].value = currentDEC;
608 lastRA = currentRA;
609 lastDEC = currentDEC;
610 IDSetNumber (&eqNum, NULL);
613 break;
615 case IPS_BUSY:
616 currentRA = GetRA();
617 currentDEC = GetDec();
618 dx = targetRA - currentRA;
619 dy = targetDEC - currentDEC;
621 IDLog("targetRA is %f, currentRA is %f\n", (float) targetRA, (float) currentRA);
622 IDLog("targetDEC is %f, currentDEC is %f\n****************************\n", (float) targetDEC, (float) currentDEC);
624 eqNum.np[0].value = currentRA;
625 eqNum.np[1].value = currentDEC;
627 status = CheckCoords(targetRA, targetDEC);
629 // Wait until acknowledged or within 3.6', change as desired.
630 switch (status)
632 case 0: /* goto in progress */
633 IDSetNumber (&eqNum, NULL);
634 break;
635 case 1: /* goto complete within tolerance */
636 case 2: /* goto complete but outside tolerance */
637 currentRA = targetRA;
638 currentDEC = targetDEC;
640 /*apparentCoord( JD, (double) J2000, &currentRA, &currentDEC);*/
642 eqNum.np[0].value = currentRA;
643 eqNum.np[1].value = currentDEC;
645 eqNum.s = IPS_OK;
647 if (currentSet == 0)
649 IUResetSwitches(&OnCoordSetSw);
650 OnCoordSetSw.sp[0].s = ISS_ON;
651 IDSetNumber (&eqNum, "Slew is complete");
653 else
655 IUResetSwitches(&OnCoordSetSw);
656 OnCoordSetSw.sp[1].s = ISS_ON;
657 IDSetNumber (&eqNum, "Slew is complete. Tracking...");
660 IDSetSwitch (&OnCoordSetSw, NULL);
661 break;
663 break;
665 case IPS_OK:
666 if (PowerSw.s != IPS_OK)
667 break;
668 currentRA = GetRA();
669 currentDEC = GetDec();
671 if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
674 eqNum.np[0].value = currentRA;
675 eqNum.np[1].value = currentDEC;
676 lastRA = currentRA;
677 lastDEC = currentDEC;
678 IDSetNumber (&eqNum, NULL);
681 break;
684 case IPS_ALERT:
685 break;
688 switch (MovementSw.s)
690 case IPS_IDLE:
691 break;
692 case IPS_BUSY:
693 currentRA = GetRA();
694 currentDEC = GetDec();
696 /*apparentCoord( JD, (double) J2000, &currentRA, &currentDEC);*/
699 eqNum.np[0].value = currentRA;
700 eqNum.np[1].value = currentDEC;
702 IDSetNumber (&eqNum, NULL);
704 break;
705 case IPS_OK:
706 break;
707 case IPS_ALERT:
708 break;
713 void CelestronGPS::getBasicData()
716 targetRA = GetRA();
717 targetDEC = GetDec();
719 eqNum.np[0].value = targetRA;
720 eqNum.np[1].value = targetDEC;
722 IDSetNumber(&eqNum, NULL);
726 void CelestronGPS::powerTelescope()
729 switch (PowerSw.sp[0].s)
731 case ISS_ON:
733 if (ConnectTel(Port.tp[0].text) < 0)
735 PowerS[0].s = ISS_OFF;
736 PowerS[1].s = ISS_ON;
737 IDSetSwitch (&PowerSw, "Error connecting to port %s", Port.tp[0].text);
738 return;
741 PowerSw.s = IPS_OK;
742 IDSetSwitch (&PowerSw, "Telescope is online. Retrieving basic data...");
743 getBasicData();
744 break;
746 case ISS_OFF:
747 IDSetSwitch (&PowerSw, "Telescope is offline.");
748 IDLog("Telescope is offline.");
749 DisconnectTel();
750 break;
755 void CelestronGPS::slewError(int slewCode)
757 eqNum.s = IPS_IDLE;
759 switch (slewCode)
761 case 1:
762 IDSetNumber (&eqNum, "Invalid newDec in SlewToCoords");
763 break;
764 case 2:
765 IDSetNumber (&eqNum, "RA count overflow in SlewToCoords");
766 break;
767 case 3:
768 IDSetNumber (&eqNum, "Dec count overflow in SlewToCoords");
769 break;
770 case 4:
771 IDSetNumber (&eqNum, "No acknowledgement from telescope after SlewToCoords");
772 break;
773 default:
774 IDSetNumber (&eqNum, "Unknown error");
775 break;