1 #if 0
2 IEQ45 Basic Driver
3 Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes
4 from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com)
5 
6 This library is free software;
7 you can redistribute it and / or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation;
10 either
11 version 2.1 of the License, or (at your option) any later version.
12 
13 This library is distributed in the hope that it will be useful,
14      but WITHOUT ANY WARRANTY;
15 without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 Lesser General Public License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library;
21 if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110 - 1301  USA
23 
24 #endif
25 
26 #include "ieq45.h"
27 
28 #include "config.h"
29 #include "ieq45driver.h"
30 #include "indicom.h"
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <math.h>
35 #include <unistd.h>
36 
37 
38 #include <memory>
39 
40 const int POLLMS_OVERRIDE  = 100;     // Period of update, 1 second.
41 const char *mydev = "IEQ45"; // Name of our device.
42 
43 const char *BASIC_GROUP   = "Main Control"; // Main Group
44 const char *OPTIONS_GROUP = "Options";      // Options Group
45 
46 /* Handy Macros */
47 #define currentRA  EquatorialCoordsRN[0].value
48 #define currentDEC EquatorialCoordsRN[1].value
49 
50 static void ISPoll(void *);
51 static void retry_connection(void *);
52 
53 static class Loader
54 {
55     std::unique_ptr<IEQ45Basic> telescope;
56 public:
Loader()57     Loader()
58     {
59         telescope.reset(new IEQ45Basic());
60         IEAddTimer(POLLMS_OVERRIDE, ISPoll, nullptr);
61     }
62 } loader;
63 
64 /**************************************************************************************
65 **
66 ***************************************************************************************/
ISPoll(void * p)67 void ISPoll(void *p)
68 {
69     INDI_UNUSED(p);
70 
71     telescope->ISPoll();
72     IEAddTimer(POLLMS_OVERRIDE, ISPoll, nullptr);
73 }
74 
75 /**************************************************************************************
76 ** IEQ45 Basic constructor
77 ***************************************************************************************/
IEQ45Basic()78 IEQ45Basic::IEQ45Basic()
79 {
80     init_properties();
81 
82     lastSet    = -1;
83     fd         = -1;
84     simulation = false;
85     lastRA     = 0;
86     lastDEC    = 0;
87     currentSet = 0;
88 
89     IDLog("Initializing from IEQ45 device...\n");
90     IDLog("Driver Version: 0.1 (2011-11-07)\n");
91 
92     enable_simulation(false);
93 }
94 
95 /**************************************************************************************
96 **
97 ***************************************************************************************/
~IEQ45Basic()98 IEQ45Basic::~IEQ45Basic()
99 {
100 }
101 
102 /**************************************************************************************
103 ** Initialize all properties & set default values.
104 ***************************************************************************************/
init_properties()105 void IEQ45Basic::init_properties()
106 {
107     // Connection#include <stdio.h>
108 #include <string.h>
109     IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF);
110     IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON);
111     IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW,
112                        ISR_1OFMANY, 60, IPS_IDLE);
113 
114     // Coord Set
115     IUFillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON);
116     IUFillSwitch(&OnCoordSetS[1], "SYNC", "Sync", ISS_OFF);
117     IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP,
118                        IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
119 
120     //Track MODE
121     IUFillSwitch(&TrackModeS[0], "SIDEREAL", "Sidereal", ISS_ON);
122     IUFillSwitch(&TrackModeS[1], "LUNAR", "Lunar", ISS_OFF);
123     IUFillSwitch(&TrackModeS[2], "SOLAR", "Solar", ISS_OFF);
124     IUFillSwitch(&TrackModeS[3], "ZERO", "Stop", ISS_OFF);
125     IUFillSwitchVector(&TrackModeSP, TrackModeS, NARRAY(TrackModeS), mydev, "TRACK_MODE", "Track Mode", BASIC_GROUP,
126                        IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
127 
128     // Abort
129     IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF);
130     IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track",
131                        BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
132 
133     // Port
134     IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyS0");
135     IUFillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
136 
137     // Equatorial Coords
138     IUFillNumber(&EquatorialCoordsRN[0], "RA", "RA  H:M:S", "%10.6m", 0., 24., 0., 0.);
139     IUFillNumber(&EquatorialCoordsRN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
140     IUFillNumberVector(&EquatorialCoordsRNP, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), mydev,
141                        "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
142 }
143 
144 /**************************************************************************************
145 ** Define IEQ45 Basic properties to clients.
146 ***************************************************************************************/
ISGetProperties(const char * dev)147 void IEQ45Basic::ISGetProperties(const char *dev)
148 {
149     if (dev != nullptr && strcmp(mydev, dev))
150         return;
151 
152     // Main Control
153     IDDefSwitch(&ConnectSP, nullptr);
154     IDDefText(&PortTP, nullptr);
155     IDDefNumber(&EquatorialCoordsRNP, nullptr);
156     IDDefSwitch(&OnCoordSetSP, nullptr);
157     IDDefSwitch(&TrackModeSP, nullptr);
158     IDDefSwitch(&AbortSlewSP, nullptr);
159 }
160 
161 /**************************************************************************************
162 ** Process Text properties
163 ***************************************************************************************/
ISNewText(const char * dev,const char * name,char * texts[],char * names[],int n)164 void IEQ45Basic::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
165 {
166     // Ignore if not ours
167     if (strcmp(dev, mydev))
168         return;
169 
170     // ===================================
171     // Port Name
172     // ===================================
173     if (!strcmp(name, PortTP.name))
174     {
175         if (IUUpdateText(&PortTP, texts, names, n) < 0)
176             return;
177 
178         PortTP.s = IPS_OK;
179         IDSetText(&PortTP, nullptr);
180         return;
181     }
182 
183     if (is_connected() == false)
184     {
185         IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands.");
186         reset_all_properties();
187         return;
188     }
189 }
190 
191 /**************************************************************************************
192 **
193 ***************************************************************************************/
ISNewNumber(const char * dev,const char * name,double values[],char * names[],int n)194 void IEQ45Basic::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
195 {
196     // Ignore if not ours
197     if (strcmp(dev, mydev))
198         return;
199 
200     if (is_connected() == false)
201     {
202         IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands.");
203         reset_all_properties();
204         return;
205     }
206 
207     // ===================================
208     // Equatorial Coords
209     // ===================================
210     if (!strcmp(name, EquatorialCoordsRNP.name))
211     {
212         int i = 0, nset = 0, error_code = 0;
213         double newRA = 0, newDEC = 0;
214 
215         for (nset = i = 0; i < n; i++)
216         {
217             INumber *eqp = IUFindNumber(&EquatorialCoordsRNP, names[i]);
218             if (eqp == &EquatorialCoordsRN[0])
219             {
220                 newRA = values[i];
221                 nset += newRA >= 0 && newRA <= 24.0;
222             }
223             else if (eqp == &EquatorialCoordsRN[1])
224             {
225                 newDEC = values[i];
226                 nset += newDEC >= -90.0 && newDEC <= 90.0;
227             }
228         }
229 
230         if (nset == 2)
231         {
232             char RAStr[32], DecStr[32];
233 
234             fs_sexa(RAStr, newRA, 2, 3600);
235             fs_sexa(DecStr, newDEC, 2, 3600);
236 
237 #ifdef INDI_DEBUG
238             IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC);
239             IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);
240 #endif
241 
242             if (!simulation &&
243                 ((error_code = setObjectRA(fd, newRA)) < 0 || (error_code = setObjectDEC(fd, newDEC)) < 0))
244             {
245                 handle_error(&EquatorialCoordsRNP, error_code, "Setting RA/DEC");
246                 return;
247             }
248 
249             targetRA  = newRA;
250             targetDEC = newDEC;
251 
252             if (process_coords() == false)
253             {
254                 EquatorialCoordsRNP.s = IPS_ALERT;
255                 IDSetNumber(&EquatorialCoordsRNP, nullptr);
256             }
257         } // end nset
258         else
259         {
260             EquatorialCoordsRNP.s = IPS_ALERT;
261             IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid");
262         }
263 
264         return;
265     } /* end EquatorialCoordsWNP */
266 }
267 
268 /**************************************************************************************
269 **
270 ***************************************************************************************/
ISNewSwitch(const char * dev,const char * name,ISState * states,char * names[],int n)271 void IEQ45Basic::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
272 {
273     // ignore if not ours //
274     if (strcmp(mydev, dev))
275         return;
276 
277     // ===================================
278     // Connect Switch
279     // ===================================
280     if (!strcmp(name, ConnectSP.name))
281     {
282         if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
283             return;
284 
285         connect_telescope();
286         return;
287     }
288 
289     if (is_connected() == false)
290     {
291         IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands.");
292         reset_all_properties();
293         return;
294     }
295 
296     // ===================================
297     // Coordinate Set
298     // ===================================
299     if (!strcmp(name, OnCoordSetSP.name))
300     {
301         if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0)
302             return;
303 
304         currentSet     = get_switch_index(&OnCoordSetSP);
305         OnCoordSetSP.s = IPS_OK;
306         IDSetSwitch(&OnCoordSetSP, nullptr);
307     }
308 
309     // ===================================
310     // Track Mode Set
311     // ===================================
312     if (!strcmp(name, TrackModeSP.name))
313     {
314         if (IUUpdateSwitch(&TrackModeSP, states, names, n) < 0)
315             return;
316 
317         int trackMode = get_switch_index(&TrackModeSP);
318         selectTrackingMode(fd, trackMode);
319         TrackModeSP.s = IPS_OK;
320         IDSetSwitch(&TrackModeSP, nullptr);
321     }
322 
323     // ===================================
324     // Abort slew
325     // ===================================
326     if (!strcmp(name, AbortSlewSP.name))
327     {
328         IUResetSwitch(&AbortSlewSP);
329         abortSlew(fd);
330 
331         if (EquatorialCoordsRNP.s == IPS_BUSY)
332         {
333             AbortSlewSP.s         = IPS_OK;
334             EquatorialCoordsRNP.s = IPS_IDLE;
335             IDSetSwitch(&AbortSlewSP, "Slew aborted.");
336             IDSetNumber(&EquatorialCoordsRNP, nullptr);
337         }
338 
339         return;
340     }
341 }
342 
343 /**************************************************************************************
344 ** Retry connecting to the telescope on error. Give up if there is no hope.
345 ***************************************************************************************/
handle_error(INumberVectorProperty * nvp,int err,const char * msg)346 void IEQ45Basic::handle_error(INumberVectorProperty *nvp, int err, const char *msg)
347 {
348     nvp->s = IPS_ALERT;
349 
350     /* First check to see if the telescope is connected */
351     if (check_IEQ45_connection(fd))
352     {
353         /* The telescope is off locally */
354         ConnectS[0].s = ISS_OFF;
355         ConnectS[1].s = ISS_ON;
356         ConnectSP.s   = IPS_BUSY;
357         IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
358 
359         IDSetNumber(nvp, nullptr);
360         IEAddTimer(10000, retry_connection, &fd);
361         return;
362     }
363 
364     /* If the error is a time out, then the device doesn't support this property */
365     if (err == -2)
366     {
367         nvp->s = IPS_ALERT;
368         IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
369     }
370     else
371         /* Changing property failed, user should retry. */
372         IDSetNumber(nvp, "%s failed.", msg);
373 
374     fault = true;
375 }
376 
377 /**************************************************************************************
378 ** Set all properties to idle and reset most switches to clean state.
379 ***************************************************************************************/
reset_all_properties()380 void IEQ45Basic::reset_all_properties()
381 {
382     ConnectSP.s           = IPS_IDLE;
383     OnCoordSetSP.s        = IPS_IDLE;
384     TrackModeSP.s         = IPS_IDLE;
385     AbortSlewSP.s         = IPS_IDLE;
386     PortTP.s              = IPS_IDLE;
387     EquatorialCoordsRNP.s = IPS_IDLE;
388 
389     IUResetSwitch(&OnCoordSetSP);
390     IUResetSwitch(&TrackModeSP);
391     IUResetSwitch(&AbortSlewSP);
392 
393     OnCoordSetS[0].s = ISS_ON;
394     TrackModeS[0].s  = ISS_ON;
395     ConnectS[0].s    = ISS_OFF;
396     ConnectS[1].s    = ISS_ON;
397 
398     IDSetSwitch(&ConnectSP, nullptr);
399     IDSetSwitch(&OnCoordSetSP, nullptr);
400     IDSetSwitch(&TrackModeSP, nullptr);
401     IDSetSwitch(&AbortSlewSP, nullptr);
402     IDSetText(&PortTP, nullptr);
403     IDSetNumber(&EquatorialCoordsRNP, nullptr);
404 }
405 
406 /**************************************************************************************
407 **
408 ***************************************************************************************/
correct_fault()409 void IEQ45Basic::correct_fault()
410 {
411     fault = false;
412     IDMessage(mydev, "Telescope is online.");
413 }
414 
415 /**************************************************************************************
416 **
417 ***************************************************************************************/
is_connected()418 bool IEQ45Basic::is_connected()
419 {
420     if (simulation)
421         return true;
422 
423     return (ConnectSP.sp[0].s == ISS_ON);
424 }
425 
426 /**************************************************************************************
427 **
428 ***************************************************************************************/
retry_connection(void * p)429 static void retry_connection(void *p)
430 {
431     int fd = *((int *)p);
432 
433     if (check_IEQ45_connection(fd))
434         telescope->connection_lost();
435     else
436         telescope->connection_resumed();
437 }
438 
439 /**************************************************************************************
440 **
441 ***************************************************************************************/
ISPoll()442 void IEQ45Basic::ISPoll()
443 {
444     if (is_connected() == false || simulation)
445         return;
446 
447     double dx, dy;
448     int error_code = 0;
449 
450     switch (EquatorialCoordsRNP.s)
451     {
452         case IPS_IDLE:
453             getIEQ45RA(fd, &currentRA);
454             getIEQ45DEC(fd, &currentDEC);
455             if (fabs(currentRA - lastRA) > 0.01 || fabs(currentDEC - lastDEC) > 0.01)
456             {
457                 lastRA  = currentRA;
458                 lastDEC = currentDEC;
459                 IDSetNumber(&EquatorialCoordsRNP, nullptr);
460                 IDLog("IDLE update coord\n");
461             }
462             break;
463 
464         case IPS_BUSY:
465             getIEQ45RA(fd, &currentRA);
466             getIEQ45DEC(fd, &currentDEC);
467             dx = targetRA - currentRA;
468             dy = targetDEC - currentDEC;
469 
470             // Wait until acknowledged or within threshold
471             if (fabs(dx) <= (3 / (900.0)) && fabs(dy) <= (3 / 60.0))
472             {
473                 lastRA  = currentRA;
474                 lastDEC = currentDEC;
475                 IUResetSwitch(&OnCoordSetSP);
476                 OnCoordSetSP.s        = IPS_OK;
477                 EquatorialCoordsRNP.s = IPS_OK;
478                 IDSetNumber(&EquatorialCoordsRNP, nullptr);
479 
480                 switch (currentSet)
481                 {
482                     case IEQ45_SLEW:
483                         OnCoordSetSP.sp[IEQ45_SLEW].s = ISS_ON;
484                         IDSetSwitch(&OnCoordSetSP, "Slew is complete.");
485                         break;
486 
487                     case IEQ45_SYNC:
488                         break;
489                 }
490             }
491             else
492                 IDSetNumber(&EquatorialCoordsRNP, nullptr);
493             break;
494 
495         case IPS_OK:
496 
497             if ((error_code = getIEQ45RA(fd, &currentRA)) < 0 || (error_code = getIEQ45DEC(fd, &currentDEC)) < 0)
498             {
499                 handle_error(&EquatorialCoordsRNP, error_code, "Getting RA/DEC");
500                 return;
501             }
502 
503             if (fault == true)
504                 correct_fault();
505 
506             if ((currentRA != lastRA) || (currentDEC != lastDEC))
507             {
508                 lastRA  = currentRA;
509                 lastDEC = currentDEC;
510                 //IDLog("IPS_OK update coords %g %g\n",currentRA,currentDEC);
511                 IDSetNumber(&EquatorialCoordsRNP, nullptr);
512             }
513             break;
514 
515         case IPS_ALERT:
516             break;
517     }
518 }
519 
520 /**************************************************************************************
521 **
522 ***************************************************************************************/
process_coords()523 bool IEQ45Basic::process_coords()
524 {
525     int error_code;
526     char syncString[256];
527     char RAStr[32], DecStr[32];
528     double dx, dy;
529 
530     switch (currentSet)
531     {
532         // Slew
533         case IEQ45_SLEW:
534             lastSet = IEQ45_SLEW;
535             if (EquatorialCoordsRNP.s == IPS_BUSY)
536             {
537                 IDLog("Aborting Slew\n");
538                 abortSlew(fd);
539 
540                 // sleep for 100 mseconds
541                 usleep(100000);
542             }
543 
544             if (!simulation && (error_code = Slew(fd)))
545             {
546                 slew_error(error_code);
547                 return false;
548             }
549 
550             EquatorialCoordsRNP.s = IPS_BUSY;
551             fs_sexa(RAStr, targetRA, 2, 3600);
552             fs_sexa(DecStr, targetDEC, 2, 3600);
553             IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
554             IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
555             break;
556 
557         // Sync
558         case IEQ45_SYNC:
559             lastSet               = IEQ45_SYNC;
560             EquatorialCoordsRNP.s = IPS_IDLE;
561 
562             if (!simulation && (error_code = Sync(fd, syncString) < 0))
563             {
564                 IDSetNumber(&EquatorialCoordsRNP, "Synchronization failed.");
565                 return false;
566             }
567 
568             if (simulation)
569             {
570                 EquatorialCoordsRN[0].value = EquatorialCoordsRN[0].value;
571                 EquatorialCoordsRN[1].value = EquatorialCoordsRN[1].value;
572             }
573 
574             EquatorialCoordsRNP.s = IPS_OK;
575             IDLog("Synchronization successful %s\n", syncString);
576             IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful.");
577             break;
578     }
579 
580     return true;
581 }
582 
583 /**************************************************************************************
584 **
585 ***************************************************************************************/
get_switch_index(ISwitchVectorProperty * sp)586 int IEQ45Basic::get_switch_index(ISwitchVectorProperty *sp)
587 {
588     for (int i = 0; i < sp->nsp; i++)
589         if (sp->sp[i].s == ISS_ON)
590             return i;
591 
592     return -1;
593 }
594 
595 /**************************************************************************************
596 **
597 ***************************************************************************************/
connect_telescope()598 void IEQ45Basic::connect_telescope()
599 {
600     switch (ConnectSP.sp[0].s)
601     {
602         case ISS_ON:
603 
604             if (simulation)
605             {
606                 ConnectSP.s = IPS_OK;
607                 IDSetSwitch(&ConnectSP, "Simulated telescope is online.");
608                 return;
609             }
610 
611             if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
612             {
613                 ConnectS[0].s = ISS_OFF;
614                 ConnectS[1].s = ISS_ON;
615                 IDSetSwitch(
616                     &ConnectSP,
617                     "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.",
618                     PortT[0].text);
619                 return;
620             }
621 
622             if (check_IEQ45_connection(fd))
623             {
624                 ConnectS[0].s = ISS_OFF;
625                 ConnectS[1].s = ISS_ON;
626                 IDSetSwitch(&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
627                 return;
628             }
629 
630             ConnectSP.s = IPS_OK;
631             IDSetSwitch(&ConnectSP, "Telescope is online. Retrieving basic data...");
632             get_initial_data();
633             break;
634 
635         case ISS_OFF:
636             ConnectS[0].s = ISS_OFF;
637             ConnectS[1].s = ISS_ON;
638             ConnectSP.s   = IPS_IDLE;
639             if (simulation)
640             {
641                 IDSetSwitch(&ConnectSP, "Simulated Telescope is offline.");
642                 return;
643             }
644             IDSetSwitch(&ConnectSP, "Telescope is offline.");
645             IDLog("Telescope is offline.");
646 
647             tty_disconnect(fd);
648             break;
649     }
650 }
651 
652 /**************************************************************************************
653 **
654 ***************************************************************************************/
get_initial_data()655 void IEQ45Basic::get_initial_data()
656 {
657     // Make sure short
658     checkIEQ45Format(fd);
659 
660     // Get current RA/DEC
661     getIEQ45RA(fd, &currentRA);
662     getIEQ45DEC(fd, &currentDEC);
663 
664     IDSetNumber(&EquatorialCoordsRNP, nullptr);
665 }
666 
667 /**************************************************************************************
668 **
669 ***************************************************************************************/
slew_error(int slewCode)670 void IEQ45Basic::slew_error(int slewCode)
671 {
672     OnCoordSetSP.s = IPS_IDLE;
673     IDLog("Aborting Slew\n");
674     abortSlew(fd);
675     if (slewCode == 1)
676         IDSetSwitch(&OnCoordSetSP, "Object below horizon.");
677     else if (slewCode == 2)
678         IDSetSwitch(&OnCoordSetSP, "Object below the minimum elevation limit.");
679     else
680         IDSetSwitch(&OnCoordSetSP, "Slew failed.");
681 }
682 
683 /**************************************************************************************
684 **
685 ***************************************************************************************/
enable_simulation(bool enable)686 void IEQ45Basic::enable_simulation(bool enable)
687 {
688     simulation = enable;
689 
690     if (simulation)
691         IDLog("Warning: Simulation is activated.\n");
692     else
693         IDLog("Simulation is disabled.\n");
694 }
695 
696 /**************************************************************************************
697 **
698 ***************************************************************************************/
connection_lost()699 void IEQ45Basic::connection_lost()
700 {
701     ConnectSP.s = IPS_IDLE;
702     IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
703     return;
704 }
705 
706 /**************************************************************************************
707 **
708 ***************************************************************************************/
connection_resumed()709 void IEQ45Basic::connection_resumed()
710 {
711     ConnectS[0].s = ISS_ON;
712     ConnectS[1].s = ISS_OFF;
713     ConnectSP.s   = IPS_OK;
714 
715     IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
716 }
717