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

« back to all changes in this revision

Viewing changes to drivers/telescope/celestrongps.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2009-02-13 20:26:22 UTC
  • Revision ID: james.westby@ubuntu.com-20090213202622-hz9rulzxa2akq5vw
Tags: upstream-0.6
ImportĀ upstreamĀ versionĀ 0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if 0
 
2
    Celestron GPS
 
3
    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 
 
19
#endif
 
20
 
 
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>
 
28
 
 
29
#include "celestronprotocol.h"
 
30
#include "celestrongps.h"
 
31
 
 
32
#define mydev           "Celestron GPS"
 
33
 
 
34
/* Handy Macros */
 
35
#define currentRA       EquatorialCoordsRN[0].value
 
36
#define currentDEC      EquatorialCoordsRN[1].value
 
37
#define targetRA        EquatorialCoordsWN[0].value
 
38
#define targetDEC       EquatorialCoordsWN[1].value
 
39
 
 
40
/* Enable to log debug statements 
 
41
#define CELESTRON_DEBUG 1
 
42
*/
 
43
 
 
44
CelestronGPS *telescope = NULL;
 
45
 
 
46
 
 
47
/* There is _one_ binary for all LX200 drivers, but each binary is renamed
 
48
** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
 
49
** fetch from std args the binary name and ISInit will create the apporpiate
 
50
** device afterwards. If the binary name does not match any known devices,
 
51
** we simply create a generic device
 
52
*/
 
53
extern char* me;
 
54
 
 
55
#define COMM_GROUP      "Communication"
 
56
#define BASIC_GROUP     "Main Control"
 
57
#define MOVE_GROUP      "Movement Control"
 
58
 
 
59
static void ISPoll(void *);
 
60
 
 
61
/*INDI controls */
 
62
static ISwitch SlewModeS[]       = {{"Slew", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0, 0}};
 
63
 
 
64
/* Equatorial Coordinates: Request */
 
65
static INumber EquatorialCoordsWN[] = {    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
 
66
static INumberVectorProperty EquatorialCoordsWNP = {  mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial JNow", BASIC_GROUP, IP_WO, 120, IPS_IDLE,  EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), "", 0};
 
67
 
 
68
/* Equatorial Coordinates: Info */
 
69
static INumber EquatorialCoordsRN[] = {    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
 
70
static INumberVectorProperty EquatorialCoordsRNP = {  mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE,  EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0};
 
71
 
 
72
/* Tracking precision */
 
73
INumber TrackingAccuracyN[] = {
 
74
    {"TrackRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0, 0, 0, 0},
 
75
    {"TrackDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0, 0, 0, 0},
 
76
};
 
77
static INumberVectorProperty TrackingAccuracyNP = {mydev, "Tracking Accuracy", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, TrackingAccuracyN, NARRAY(TrackingAccuracyN), "", 0};
 
78
 
 
79
/* Slew precision */
 
80
INumber SlewAccuracyN[] = {
 
81
    {"SlewRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0, 0, 0, 0},
 
82
    {"SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0, 0, 0, 0},
 
83
};
 
84
static INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0};
 
85
 
 
86
/* Fundamental group */
 
87
static ISwitch ConnectS[]          = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
 
88
static ISwitchVectorProperty ConnectSP  = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
 
89
 
 
90
static IText PortT[]                    = {{"PORT", "Port", 0, 0, 0, 0}};
 
91
static ITextVectorProperty PortTP               = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
 
92
 
 
93
/* Movement group */
 
94
static ISwitch OnCoordSetS[]     = {{"SLEW", "Slew", ISS_ON, 0 , 0}, {"TRACK", "Track", ISS_OFF, 0, 0}, {"SYNC", "Sync", ISS_OFF, 0, 0}};
 
95
static ISwitchVectorProperty OnCoordSetSP    = { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
 
96
 
 
97
static ISwitch AbortSlewS[]      = {{"ABORT", "Abort", ISS_OFF, 0, 0}};
 
98
static ISwitchVectorProperty AbortSlewSP     = { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0};
 
99
static ISwitchVectorProperty SlewModeSP      = { mydev, "Slew rate", "", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
 
100
 
 
101
/* Movement (Arrow keys on handset). North/South */
 
102
static ISwitch MovementNSS[]       = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
 
103
 
 
104
static ISwitchVectorProperty MovementNSSP      = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
 
105
 
 
106
/* Movement (Arrow keys on handset). West/East */
 
107
static ISwitch MovementWES[]       = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
 
108
 
 
109
static ISwitchVectorProperty MovementWESP      = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
 
110
 
 
111
 
 
112
/* send client definitions of all properties */
 
113
void ISInit()
 
114
{
 
115
  static int isInit=0;
 
116
 
 
117
 if (isInit)
 
118
  return;
 
119
 
 
120
 isInit = 1;
 
121
 
 
122
  IUSaveText(&PortT[0], "/dev/ttyS0");
 
123
  
 
124
  telescope = new CelestronGPS();
 
125
 
 
126
  IEAddTimer (POLLMS, ISPoll, NULL);
 
127
}
 
128
 
 
129
void ISGetProperties (const char *dev)
 
130
{ ISInit(); telescope->ISGetProperties(dev);}
 
131
void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
 
132
{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
 
133
void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
 
134
{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
 
135
void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
 
136
{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
 
137
void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
 
138
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
 
139
{
 
140
  INDI_UNUSED(dev);
 
141
  INDI_UNUSED(name);
 
142
  INDI_UNUSED(sizes);
 
143
  INDI_UNUSED(blobsizes);
 
144
  INDI_UNUSED(blobs);
 
145
  INDI_UNUSED(formats);
 
146
  INDI_UNUSED(names);
 
147
  INDI_UNUSED(n);
 
148
}
 
149
void ISSnoopDevice (XMLEle *root) 
 
150
{
 
151
  INDI_UNUSED(root);
 
152
}
 
153
 
 
154
/**************************************************
 
155
*** LX200 Generic Implementation
 
156
***************************************************/
 
157
 
 
158
CelestronGPS::CelestronGPS()
 
159
{
 
160
 
 
161
   lastRA = 0;
 
162
   lastDEC = 0;
 
163
   currentSet   = 0;
 
164
   lastSet      = -1;
 
165
 
 
166
   // Children call parent routines, this is the default
 
167
   IDLog("initilizaing from Celeston GPS device...\n");
 
168
 
 
169
}
 
170
 
 
171
void CelestronGPS::ISGetProperties(const char *dev)
 
172
{
 
173
 
 
174
 if (dev && strcmp (mydev, dev))
 
175
    return;
 
176
 
 
177
  // COMM_GROUP
 
178
  IDDefSwitch (&ConnectSP, NULL);
 
179
  IDDefText   (&PortTP, NULL);
 
180
  
 
181
  // BASIC_GROUP
 
182
  IDDefNumber (&EquatorialCoordsWNP, NULL);
 
183
  IDDefNumber (&EquatorialCoordsRNP, NULL);
 
184
  IDDefSwitch (&OnCoordSetSP, NULL);
 
185
  IDDefSwitch (&AbortSlewSP, NULL);
 
186
  IDDefSwitch (&SlewModeSP, NULL);
 
187
 
 
188
  // Movement group
 
189
  IDDefSwitch (&MovementNSSP, NULL);
 
190
  IDDefSwitch (&MovementWESP, NULL);
 
191
  IDDefNumber (&TrackingAccuracyNP, NULL);
 
192
  IDDefNumber (&SlewAccuracyNP, NULL);
 
193
  
 
194
  /* Send the basic data to the new client if the previous client(s) are already connected. */          
 
195
  if (ConnectSP.s == IPS_OK)
 
196
        getBasicData();
 
197
 
 
198
}
 
199
 
 
200
void CelestronGPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
 
201
{
 
202
        IText *tp;
 
203
 
 
204
        INDI_UNUSED(n);
 
205
 
 
206
        // ignore if not ours //
 
207
        if (strcmp (dev, mydev))
 
208
            return;
 
209
 
 
210
        if (!strcmp(name, PortTP.name) )
 
211
        {
 
212
          PortTP.s = IPS_OK;
 
213
 
 
214
          tp = IUFindText( &PortTP, names[0] );
 
215
          if (!tp)
 
216
           return;
 
217
 
 
218
          IUSaveText(&PortT[0], texts[0]);
 
219
          IDSetText (&PortTP, NULL);
 
220
          return;
 
221
        }
 
222
}
 
223
 
 
224
int CelestronGPS::handleCoordSet()
 
225
{
 
226
 
 
227
  int i=0;
 
228
  char RAStr[32], DecStr[32];
 
229
 
 
230
  switch (currentSet)
 
231
  {
 
232
 
 
233
    // Slew
 
234
    case 0:
 
235
          lastSet = 0;
 
236
          if (EquatorialCoordsWNP.s == IPS_BUSY)
 
237
          {
 
238
             StopNSEW();
 
239
             // sleep for 500 mseconds
 
240
             usleep(500000);
 
241
          }
 
242
 
 
243
          if ((i = SlewToCoords(targetRA, targetDEC)))
 
244
          {
 
245
            slewError(i);
 
246
            return (-1);
 
247
          }
 
248
 
 
249
          EquatorialCoordsWNP.s = IPS_BUSY;
 
250
          EquatorialCoordsRNP.s = IPS_BUSY;
 
251
          fs_sexa(RAStr, targetRA, 2, 3600);
 
252
          fs_sexa(DecStr, targetDEC, 2, 3600);
 
253
          IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
 
254
          IDSetNumber(&EquatorialCoordsRNP, NULL);
 
255
          IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
 
256
          break;
 
257
 
 
258
 
 
259
  // Track
 
260
  case 1: 
 
261
          if (EquatorialCoordsWNP.s == IPS_BUSY)
 
262
          {
 
263
              StopNSEW();
 
264
             // sleep for 500 mseconds
 
265
             usleep(500000);
 
266
          }
 
267
 
 
268
          if ( (fabs ( targetRA - currentRA ) >= (TrackingAccuracyN[0].value/(15.0*60.0))) ||
 
269
               (fabs (targetDEC - currentDEC) >= (TrackingAccuracyN[1].value)/60.0))
 
270
          {
 
271
 
 
272
                #ifdef CELESTRON_DEBUG
 
273
                IDLog("Exceeded Tracking threshold, will attempt to slew to the new target.\n");
 
274
                IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
 
275
                IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
 
276
                #endif
 
277
 
 
278
                if (( i =  SlewToCoords(targetRA, targetDEC)))
 
279
                {
 
280
                        slewError(i);
 
281
                        return (-1);
 
282
                }
 
283
                
 
284
                fs_sexa(RAStr, targetRA, 2, 3600);
 
285
                fs_sexa(DecStr, targetDEC, 2, 3600);
 
286
                EquatorialCoordsWNP.s = IPS_BUSY;
 
287
                EquatorialCoordsRNP.s = IPS_BUSY;
 
288
                IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
 
289
                IDSetNumber(&EquatorialCoordsRNP, NULL);
 
290
                IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
 
291
          }
 
292
          else
 
293
          {
 
294
            #ifdef CELESTRON_DEBUG
 
295
            IDLog("Tracking called, but tracking threshold not reached yet.\n");
 
296
            #endif
 
297
            EquatorialCoordsWNP.s = IPS_OK;
 
298
            EquatorialCoordsRNP.s = IPS_OK;
 
299
            if (lastSet != 1)
 
300
              IDSetNumber(&EquatorialCoordsWNP, "Tracking...");
 
301
            else
 
302
              IDSetNumber(&EquatorialCoordsWNP, NULL);
 
303
 
 
304
              IDSetNumber(&EquatorialCoordsRNP, NULL);
 
305
          }
 
306
          lastSet = 1;
 
307
      break;
 
308
      
 
309
    // Sync
 
310
    case 2:
 
311
          lastSet = 2;
 
312
          OnCoordSetSP.s = IPS_OK;
 
313
          SyncToCoords(targetRA, targetDEC);
 
314
          EquatorialCoordsWNP.s = IPS_OK;
 
315
          EquatorialCoordsRNP.s = IPS_OK;
 
316
          IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
 
317
          IDSetNumber(&EquatorialCoordsRNP, NULL);
 
318
          break;
 
319
   }
 
320
 
 
321
   return (0);
 
322
 
 
323
}
 
324
 
 
325
void CelestronGPS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
 
326
{
 
327
        double newRA=0, newDEC=0;
 
328
 
 
329
        // ignore if not ours //
 
330
        if (strcmp (dev, mydev))
 
331
            return;
 
332
 
 
333
        struct tm *tp;
 
334
        time_t t;
 
335
 
 
336
        time (&t);
 
337
        tp = gmtime (&t);
 
338
 
 
339
        if (!strcmp (name, TrackingAccuracyNP.name))
 
340
        {
 
341
                if (!IUUpdateNumber(&TrackingAccuracyNP, values, names, n))
 
342
                {
 
343
                        TrackingAccuracyNP.s = IPS_OK;
 
344
                        IDSetNumber(&TrackingAccuracyNP, NULL);
 
345
                        return;
 
346
                }
 
347
                
 
348
                TrackingAccuracyNP.s = IPS_ALERT;
 
349
                IDSetNumber(&TrackingAccuracyNP, "unknown error while setting tracking precision");
 
350
                return;
 
351
        }
 
352
 
 
353
        if (!strcmp(name, SlewAccuracyNP.name))
 
354
        {
 
355
                IUUpdateNumber(&SlewAccuracyNP, values, names, n);
 
356
                {
 
357
                        SlewAccuracyNP.s = IPS_OK;
 
358
                        IDSetNumber(&SlewAccuracyNP, NULL);
 
359
                        return;
 
360
                }
 
361
                
 
362
                SlewAccuracyNP.s = IPS_ALERT;
 
363
                IDSetNumber(&SlewAccuracyNP, "unknown error while setting slew precision");
 
364
                return;
 
365
        }
 
366
 
 
367
        if (!strcmp (name, EquatorialCoordsWNP.name))
 
368
        {
 
369
          int i=0, nset=0;
 
370
 
 
371
          if (checkPower(&EquatorialCoordsWNP))
 
372
           return;
 
373
 
 
374
            for (nset = i = 0; i < n; i++)
 
375
            {
 
376
                INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
 
377
                if (eqp == &EquatorialCoordsWN[0])
 
378
                {
 
379
                    newRA = values[i];
 
380
                    nset += newRA >= 0 && newRA <= 24.0;
 
381
                } else if (eqp == &EquatorialCoordsWN[1])
 
382
                {
 
383
                    newDEC = values[i];
 
384
                    nset += newDEC >= -90.0 && newDEC <= 90.0;
 
385
                }
 
386
            }
 
387
 
 
388
          if (nset == 2)
 
389
          {
 
390
           //EquatorialCoordsNP.s = IPS_BUSY;
 
391
 
 
392
           tp->tm_mon   += 1;
 
393
           tp->tm_year  += 1900;
 
394
 
 
395
           targetRA  = newRA;
 
396
           targetDEC = newDEC;
 
397
               
 
398
           if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
 
399
           {
 
400
                IUResetSwitch(&MovementNSSP);
 
401
                IUResetSwitch(&MovementWESP);
 
402
                MovementNSSP.s = MovementWESP.s = IPS_IDLE;
 
403
                IDSetSwitch(&MovementNSSP, NULL);
 
404
                IDSetSwitch(&MovementWESP, NULL);
 
405
           }
 
406
           
 
407
               if (handleCoordSet())
 
408
               {
 
409
                EquatorialCoordsWNP.s = IPS_ALERT;
 
410
                IDSetNumber(&EquatorialCoordsWNP, NULL);
 
411
               }
 
412
            }
 
413
            else
 
414
            {
 
415
                EquatorialCoordsWNP.s = IPS_ALERT;
 
416
                IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid.");
 
417
            }
 
418
 
 
419
            return;
 
420
         }
 
421
}
 
422
 
 
423
void CelestronGPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
 
424
{
 
425
 
 
426
        int index;
 
427
 
 
428
        INDI_UNUSED(names);
 
429
 
 
430
        // ignore if not ours //
 
431
        if (strcmp (dev, mydev))
 
432
            return;
 
433
 
 
434
        // FIRST Switch ALWAYS for power
 
435
        if (!strcmp (name, ConnectSP.name))
 
436
        {
 
437
         if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return;
 
438
         connectTelescope();
 
439
         return;
 
440
        }
 
441
 
 
442
        if (!strcmp(name, OnCoordSetSP.name))
 
443
        {
 
444
          if (checkPower(&OnCoordSetSP))
 
445
           return;
 
446
 
 
447
          
 
448
          if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return;
 
449
          currentSet = getOnSwitch(&OnCoordSetSP);
 
450
        }
 
451
        
 
452
        // Abort Slew
 
453
        if (!strcmp (name, AbortSlewSP.name))
 
454
        {
 
455
          if (checkPower(&AbortSlewSP))
 
456
          {
 
457
            AbortSlewSP.s = IPS_ALERT;
 
458
            IDSetSwitch(&AbortSlewSP, NULL);
 
459
            return;
 
460
          }
 
461
          
 
462
          IUResetSwitch(&AbortSlewSP);
 
463
          StopNSEW();
 
464
 
 
465
            if (EquatorialCoordsWNP.s == IPS_BUSY)
 
466
            {
 
467
                AbortSlewSP.s = IPS_OK;
 
468
                EquatorialCoordsWNP.s       = IPS_IDLE;
 
469
                EquatorialCoordsRNP.s       = IPS_IDLE;
 
470
                IDSetSwitch(&AbortSlewSP, "Slew aborted.");
 
471
                IDSetNumber(&EquatorialCoordsWNP, NULL);
 
472
                IDSetNumber(&EquatorialCoordsRNP, NULL);
 
473
            }
 
474
            else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
 
475
            {
 
476
                MovementNSSP.s  = MovementWESP.s =  IPS_IDLE; 
 
477
        
 
478
                AbortSlewSP.s = IPS_OK;         
 
479
                EquatorialCoordsRNP.s       = IPS_IDLE;
 
480
                IUResetSwitch(&MovementNSSP);
 
481
                IUResetSwitch(&MovementWESP);
 
482
                IUResetSwitch(&AbortSlewSP);
 
483
 
 
484
                IDSetSwitch(&AbortSlewSP, "Slew aborted.");
 
485
                IDSetSwitch(&MovementNSSP, NULL);
 
486
                IDSetSwitch(&MovementWESP, NULL);
 
487
                IDSetNumber(&EquatorialCoordsRNP, NULL);
 
488
            }
 
489
            else
 
490
            {
 
491
                AbortSlewSP.s = IPS_OK;
 
492
                IDSetSwitch(&AbortSlewSP, NULL);
 
493
            }
 
494
 
 
495
            return;
 
496
        }
 
497
 
 
498
        // Slew mode
 
499
        if (!strcmp (name, SlewModeSP.name))
 
500
        {
 
501
          if (checkPower(&SlewModeSP))
 
502
           return;
 
503
 
 
504
          IUResetSwitch(&SlewModeSP);
 
505
          IUUpdateSwitch(&SlewModeSP, states, names, n);
 
506
          index = getOnSwitch(&SlewModeSP);
 
507
          SetRate(index);
 
508
          
 
509
          SlewModeSP.s = IPS_OK;
 
510
          IDSetSwitch(&SlewModeSP, NULL);
 
511
          return;
 
512
        }
 
513
 
 
514
        // Movement (North/South)
 
515
        if (!strcmp (name, MovementNSSP.name))
 
516
        {
 
517
          if (checkPower(&MovementNSSP))
 
518
           return;
 
519
 
 
520
         int last_move=-1;
 
521
         int current_move = -1;
 
522
 
 
523
        // -1 means all off previously
 
524
         last_move = getOnSwitch(&MovementNSSP);
 
525
 
 
526
         if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0)
 
527
                return;
 
528
 
 
529
        current_move = getOnSwitch(&SlewModeSP);
 
530
 
 
531
        // Previosuly active switch clicked again, so let's stop.
 
532
        if (current_move == last_move)
 
533
        {
 
534
                StopSlew((current_move == 0) ? NORTH : SOUTH);
 
535
                IUResetSwitch(&MovementNSSP);
 
536
                MovementNSSP.s = IPS_IDLE;
 
537
                IDSetSwitch(&MovementNSSP, NULL);
 
538
                return;
 
539
        }
 
540
 
 
541
        #ifdef CELESTRON_DEBUG
 
542
        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
 
543
        #endif
 
544
 
 
545
        // 0 (North) or 1 (South)
 
546
        last_move      = current_move;
 
547
 
 
548
        // Correction for Celestron Driver: North 0 - South 3
 
549
        current_move = (current_move == 0) ? NORTH : SOUTH;
 
550
 
 
551
        StartSlew(current_move);
 
552
        
 
553
          MovementNSSP.s = IPS_BUSY;
 
554
          IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == NORTH) ? "North" : "South");
 
555
          return;
 
556
        }
 
557
 
 
558
        // Movement (West/East)
 
559
        if (!strcmp (name, MovementWESP.name))
 
560
        {
 
561
          if (checkPower(&MovementWESP))
 
562
           return;
 
563
 
 
564
         int last_move=-1;
 
565
         int current_move = -1;
 
566
 
 
567
        // -1 means all off previously
 
568
         last_move = getOnSwitch(&MovementWESP);
 
569
 
 
570
         if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0)
 
571
                return;
 
572
 
 
573
        current_move = getOnSwitch(&SlewModeSP);
 
574
 
 
575
        // Previosuly active switch clicked again, so let's stop.
 
576
        if (current_move == last_move)
 
577
        {
 
578
                StopSlew((current_move ==0) ? WEST : EAST);
 
579
                IUResetSwitch(&MovementWESP);
 
580
                MovementWESP.s = IPS_IDLE;
 
581
                IDSetSwitch(&MovementWESP, NULL);
 
582
                return;
 
583
        }
 
584
 
 
585
        #ifdef CELESTRON_DEBUG
 
586
        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
 
587
        #endif
 
588
 
 
589
        // 0 (West) or 1 (East)
 
590
        last_move      = current_move;
 
591
 
 
592
        // Correction for Celestron Driver: West 1 - East 2
 
593
        current_move = (current_move == 0) ? WEST : EAST;
 
594
 
 
595
        StartSlew(current_move);
 
596
        
 
597
          MovementWESP.s = IPS_BUSY;
 
598
          IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == WEST) ? "West" : "East");
 
599
          return;
 
600
        }
 
601
}
 
602
 
 
603
 
 
604
int CelestronGPS::getOnSwitch(ISwitchVectorProperty *sp)
 
605
{
 
606
 for (int i=0; i < sp->nsp ; i++)
 
607
     if (sp->sp[i].s == ISS_ON)
 
608
      return i;
 
609
 
 
610
 return -1;
 
611
}
 
612
 
 
613
 
 
614
int CelestronGPS::checkPower(ISwitchVectorProperty *sp)
 
615
{
 
616
  if (ConnectSP.s != IPS_OK)
 
617
  {
 
618
    if (!strcmp(sp->label, ""))
 
619
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->name);
 
620
    else
 
621
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->label);
 
622
       
 
623
    sp->s = IPS_IDLE;
 
624
    IDSetSwitch(sp, NULL);
 
625
    return -1;
 
626
  }
 
627
 
 
628
  return 0;
 
629
}
 
630
 
 
631
int CelestronGPS::checkPower(INumberVectorProperty *np)
 
632
{
 
633
  if (ConnectSP.s != IPS_OK)
 
634
  {
 
635
    if (!strcmp(np->label, ""))
 
636
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->name);
 
637
    else
 
638
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->label);
 
639
       
 
640
    np->s = IPS_IDLE;
 
641
    IDSetNumber(np, NULL);
 
642
    return -1;
 
643
  }
 
644
  return 0;
 
645
}
 
646
 
 
647
int CelestronGPS::checkPower(ITextVectorProperty *tp)
 
648
{
 
649
 
 
650
  if (ConnectSP.s != IPS_OK)
 
651
  {
 
652
    if (!strcmp(tp->label, ""))
 
653
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->name);
 
654
    else
 
655
       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->label);
 
656
       
 
657
    tp->s = IPS_IDLE;
 
658
    IDSetText(tp, NULL);
 
659
    return -1;
 
660
  }
 
661
 
 
662
  return 0;
 
663
 
 
664
}
 
665
 
 
666
void CelestronGPS::ISPoll()
 
667
{
 
668
       double dx, dy;
 
669
       int status;
 
670
 
 
671
        switch (EquatorialCoordsWNP.s)
 
672
        {
 
673
        case IPS_IDLE:
 
674
        if (ConnectSP.s != IPS_OK)
 
675
         break;
 
676
        currentRA = GetRA();
 
677
        currentDEC = GetDec();
 
678
 
 
679
        if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
 
680
        {
 
681
                lastRA  = currentRA;
 
682
                lastDEC = currentDEC;
 
683
                IDSetNumber (&EquatorialCoordsRNP, NULL);
 
684
 
 
685
        }
 
686
        break;
 
687
 
 
688
        case IPS_BUSY:
 
689
            currentRA = GetRA();
 
690
            currentDEC = GetDec();
 
691
            dx = targetRA - currentRA;
 
692
            dy = targetDEC - currentDEC;
 
693
 
 
694
            #ifdef CELESTRON_DEBUG
 
695
            IDLog("targetRA is %f, currentRA is %f\n", (float) targetRA, (float) currentRA);
 
696
            IDLog("targetDEC is %f, currentDEC is %f\n****************************\n", (float) targetDEC, (float) currentDEC);
 
697
            #endif
 
698
 
 
699
            status = CheckCoords(targetRA, targetDEC, SlewAccuracyN[0].value/(15.0*60.0) , SlewAccuracyN[1].value/60.0);
 
700
 
 
701
            // Wait until acknowledged or within 3.6', change as desired.
 
702
            switch (status)
 
703
            {
 
704
            case 0:             /* goto in progress */
 
705
                IDSetNumber (&EquatorialCoordsRNP, NULL);
 
706
                break;
 
707
            case 1:             /* goto complete within tolerance */
 
708
            case 2:             /* goto complete but outside tolerance */
 
709
                currentRA = targetRA;
 
710
                currentDEC = targetDEC;
 
711
 
 
712
                EquatorialCoordsWNP.s = IPS_OK;
 
713
                EquatorialCoordsRNP.s = IPS_OK;
 
714
 
 
715
                if (currentSet == 0)
 
716
                {
 
717
                  IDSetNumber (&EquatorialCoordsWNP, "Slew is complete.");
 
718
                  IDSetNumber (&EquatorialCoordsRNP, NULL);
 
719
                }
 
720
                else
 
721
                {
 
722
                  IDSetNumber (&EquatorialCoordsWNP, "Slew is complete. Tracking...");
 
723
                  IDSetNumber (&EquatorialCoordsRNP, NULL);
 
724
                }
 
725
                
 
726
                break;
 
727
            }   
 
728
            break;
 
729
 
 
730
        case IPS_OK:
 
731
        if (ConnectSP.s != IPS_OK)
 
732
         break;
 
733
        currentRA = GetRA();
 
734
        currentDEC = GetDec();
 
735
 
 
736
        if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
 
737
        {
 
738
                lastRA  = currentRA;
 
739
                lastDEC = currentDEC;
 
740
                IDSetNumber (&EquatorialCoordsRNP, NULL);
 
741
 
 
742
        }
 
743
        break;
 
744
 
 
745
 
 
746
        case IPS_ALERT:
 
747
            break;
 
748
        }
 
749
 
 
750
        switch (MovementNSSP.s)
 
751
        {
 
752
          case IPS_IDLE:
 
753
           break;
 
754
         case IPS_BUSY:
 
755
             currentRA = GetRA();
 
756
             currentDEC = GetDec();
 
757
             IDSetNumber (&EquatorialCoordsRNP, NULL);
 
758
 
 
759
             break;
 
760
         case IPS_OK:
 
761
           break;
 
762
         case IPS_ALERT:
 
763
           break;
 
764
         }
 
765
 
 
766
        switch (MovementWESP.s)
 
767
        {
 
768
          case IPS_IDLE:
 
769
           break;
 
770
         case IPS_BUSY:
 
771
             currentRA = GetRA();
 
772
             currentDEC = GetDec();
 
773
             IDSetNumber (&EquatorialCoordsRNP, NULL);
 
774
 
 
775
             break;
 
776
         case IPS_OK:
 
777
           break;
 
778
         case IPS_ALERT:
 
779
           break;
 
780
         }
 
781
 
 
782
}
 
783
 
 
784
void CelestronGPS::getBasicData()
 
785
{
 
786
 
 
787
  currentRA = GetRA();
 
788
  currentDEC = GetDec();
 
789
 
 
790
  IDSetNumber(&EquatorialCoordsRNP, NULL);
 
791
 
 
792
}
 
793
 
 
794
void CelestronGPS::connectTelescope()
 
795
{
 
796
 
 
797
     switch (ConnectSP.sp[0].s)
 
798
     {
 
799
      case ISS_ON:
 
800
 
 
801
         if (ConnectTel(PortTP.tp[0].text) < 0)
 
802
         {
 
803
           ConnectS[0].s = ISS_OFF;
 
804
           ConnectS[1].s = ISS_ON;
 
805
           IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to the port.", PortTP.tp[0].text);
 
806
           return;
 
807
         }
 
808
 
 
809
        ConnectSP.s = IPS_OK;
 
810
        IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
 
811
        getBasicData();
 
812
        break;
 
813
 
 
814
     case ISS_OFF:
 
815
         IDSetSwitch (&ConnectSP, "Telescope is offline.");
 
816
         IDLog("Telescope is offline.");
 
817
         DisconnectTel();
 
818
         break;
 
819
 
 
820
    }
 
821
}
 
822
 
 
823
void CelestronGPS::slewError(int slewCode)
 
824
{
 
825
    EquatorialCoordsWNP.s = IPS_ALERT;
 
826
 
 
827
    switch (slewCode)
 
828
    {
 
829
      case 1:
 
830
       IDSetNumber (&EquatorialCoordsWNP, "Invalid newDec in SlewToCoords");
 
831
       break;
 
832
      case 2:
 
833
       IDSetNumber (&EquatorialCoordsWNP, "RA count overflow in SlewToCoords");
 
834
       break;
 
835
      case 3:
 
836
       IDSetNumber (&EquatorialCoordsWNP, "Dec count overflow in SlewToCoords");
 
837
       break;
 
838
      case 4:
 
839
       IDSetNumber (&EquatorialCoordsWNP, "No acknowledgment from telescope after SlewToCoords");
 
840
       break;
 
841
      default:
 
842
       IDSetNumber (&EquatorialCoordsWNP, "Unknown error");
 
843
       break;
 
844
    }
 
845
 
 
846
}