Instrument Neutral Distributed Interface INDI  2.0.2
paramount.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3  2021 Chris Lewicki. Refactor of TCP connections and error handling
4 
5  Driver for using TheSkyX Pro Scripted operations for mounts via the TCP server.
6  While this technically can operate any mount connected to the TheSkyX Pro, it is
7  intended for Paramount mounts control.
8 
9  Ref TheSky Functions:
10  https://www.bisque.com/wp-content/scripttheskyx/classsky6_r_a_s_c_o_m_tele.html
11 
12  This library is free software; you can redistribute it and/or
13  modify it under the terms of the GNU Library General Public
14  License version 2 as published by the Free Software Foundation.
15  .
16  This library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  Library General Public License for more details.
20  .
21  You should have received a copy of the GNU Library General Public License
22  along with this library; see the file COPYING.LIB. If not, write to
23  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  Boston, MA 02110-1301, USA.
25 *******************************************************************************/
26 
27 /*******************************************************************************
28  * TODO for improving / completing the driver
29  *
30  * 1. SlewToAZAlt()
31  * 2. GetAzAlt()
32  * 3. (3) Presets for SlewToAZAlt positions
33  * 4. DoCommand(16) get/set atmospheric pressure for interfacing with other INDI devices
34 *******************************************************************************/
35 
36 #include "paramount.h"
37 
38 #include "indicom.h"
39 
40 #include <libnova/sidereal_time.h>
41 #include <libnova/transform.h>
42 
43 #include <cmath>
44 #include <cstring>
45 #include <memory>
46 #include <termios.h>
47 
48 // We declare an auto pointer to Paramount.
49 std::unique_ptr<Paramount> paramount_mount(new Paramount());
50 
51 #define GOTO_RATE 5 /* slew rate, degrees/s */
52 #define SLEW_RATE 0.5 /* slew rate, degrees/s */
53 #define FINE_SLEW_RATE 0.1 /* slew rate, degrees/s */
54 
55 #define GOTO_LIMIT 5.5 /* Move at GOTO_RATE until distance from target is GOTO_LIMIT degrees */
56 #define SLEW_LIMIT 1 /* Move at SLEW_LIMIT until distance from target is SLEW_LIMIT degrees */
57 
58 #define PARAMOUNT_TIMEOUT 3 /* Timeout in seconds */
59 #define PARAMOUNT_NORTH 0
60 #define PARAMOUNT_SOUTH 1
61 #define PARAMOUNT_EAST 2
62 #define PARAMOUNT_WEST 3
63 
64 #define RA_AXIS 0
65 #define DEC_AXIS 1
66 
67 /* Preset Slew Speeds */
68 #define SLEWMODES 9
69 const double slewspeeds[SLEWMODES] = { 1.0, 2.0, 4.0, 8.0, 32.0, 64.0, 128.0, 256.0, 512.0 };
70 
72 {
73  setVersion(1, 4);
74 
75  DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE");
76 
80  9);
82 
83  m_NSTimer.setSingleShot(true);
84  m_WETimer.setSingleShot(true);
85 
86  // Called when timer is up
87  m_NSTimer.callOnTimeout([this]()
88  {
90  GuideNSN[0].value = GuideNSN[1].value = 0;
91  IDSetNumber(&GuideNSNP, nullptr);
92  });
93 
94  m_WETimer.callOnTimeout([this]()
95  {
97  GuideWEN[0].value = GuideWEN[1].value = 0;
98  IDSetNumber(&GuideWENP, nullptr);
99  });
100 }
101 
103 {
104  return "Paramount";
105 }
106 
108 {
109  /* Make sure to init parent properties first */
111 
112  for (int i = 0; i < SlewRateSP.nsp - 1; i++)
113  {
114  sprintf(SlewRateSP.sp[i].label, "%.fx", slewspeeds[i]);
115  SlewRateSP.sp[i].aux = (void *)&slewspeeds[i];
116  }
117 
118  // Set 64x as default speed
119  SlewRateSP.sp[5].s = ISS_ON;
120 
121  /* How fast do we guide compared to sidereal rate */
122  IUFillNumber(&JogRateN[RA_AXIS], "JOG_RATE_WE", "W/E Rate (arcmin)", "%g", 0, 600, 60, 30);
123  IUFillNumber(&JogRateN[DEC_AXIS], "JOG_RATE_NS", "N/S Rate (arcmin)", "%g", 0, 600, 60, 30);
124  IUFillNumberVector(&JogRateNP, JogRateN, 2, getDeviceName(), "JOG_RATE", "Jog Rate", MOTION_TAB, IP_RW, 0,
125  IPS_IDLE);
126 
127  /* How fast do we guide compared to sidereal rate */
128  IUFillNumber(&GuideRateN[RA_AXIS], "GUIDE_RATE_WE", "W/E Rate", "%1.1f", 0.0, 1.0, 0.1, 0.5);
129  IUFillNumber(&GuideRateN[DEC_AXIS], "GUIDE_RATE_NS", "N/S Rate", "%1.1f", 0.0, 1.0, 0.1, 0.5);
130  IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0,
131  IPS_IDLE);
132 
133  // Homing
134  IUFillSwitch(&HomeS[0], "GO", "Go", ISS_OFF);
135  IUFillSwitchVector(&HomeSP, HomeS, 1, getDeviceName(), "TELESCOPE_HOME", "Homing", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60,
136  IPS_IDLE);
137  // Tracking Mode
138  AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
139  AddTrackMode("TRACK_SOLAR", "Solar");
140  AddTrackMode("TRACK_LUNAR", "Lunar");
141  AddTrackMode("TRACK_CUSTOM", "Custom");
142 
143  // Let's simulate it to be an F/7.5 120mm telescope with 50m 175mm guide scope
144  ScopeParametersN[0].value = 120;
145  ScopeParametersN[1].value = 900;
146  ScopeParametersN[2].value = 50;
147  ScopeParametersN[3].value = 175;
148 
150 
152 
154 
156 
157  addAuxControls();
158 
160  currentDEC = LocationN[LOCATION_LATITUDE].value > 0 ? 90 : -90;
161  return true;
162 }
163 
165 {
167 
168  if (isConnected())
169  {
170  if (isTheSkyTracking())
171  {
172  IUResetSwitch(&TrackModeSP);
173  TrackModeS[TRACK_SIDEREAL].s = ISS_ON;
175  }
176  else
177  {
178  IUResetSwitch(&TrackModeSP);
180  }
181 
182  //defineProperty(&TrackModeSP);
183  //defineProperty(&TrackRateNP);
184 
185  defineProperty(&JogRateNP);
186 
189  defineProperty(&GuideRateNP);
190 
191  // Initial HA to 0 and currentDEC (+90 or -90)
192  if (InitPark())
193  {
194  // If loading parking data is successful, we just set the default parking values.
196  SetAxis2ParkDefault(currentDEC);
197  }
198  else
199  {
200  // Otherwise, we set all parking data to default in case no parking data is found.
201  SetAxis1Park(0);
202  SetAxis2Park(currentDEC);
204  SetAxis2ParkDefault(currentDEC);
205  }
206 
207  SetParked(isTheSkyParked());
208 
209  defineProperty(&HomeSP);
210  }
211  else
212  {
213  //deleteProperty(TrackModeSP.name);
214  //deleteProperty(TrackRateNP.name);
215 
216  deleteProperty(JogRateNP.name);
217 
220  deleteProperty(GuideRateNP.name);
221  deleteProperty(HomeSP.name);
222  }
223 
224  return true;
225 }
226 
227 /*******************************************************************************
228 * Note that for all successful TheSky TCP requests, the following string is
229 * prepended to the result:
230 *
231 * |No error. Error = 0.
232 *
233 * This is true everwhere except for the Handshake(), which just returns "1" on success.
234 *
235 * In order to know when the response is complete, we append the # character in
236 * Javascript commands and read from the port until the # character is reached.
237 *******************************************************************************/
238 
240 {
241  if (isSimulation())
242  return true;
243 
244  int rc = 0, nbytes_written = 0, nbytes_read = 0;
245  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
246 
247  strncpy(pCMD,
248  "/* Java Script */"
249  "var Out;"
250  "sky6RASCOMTele.ConnectAndDoNotUnpark();"
251  "Out = sky6RASCOMTele.IsConnected + '#';",
252  MAXRBUF);
253 
254  LOGF_DEBUG("CMD: %s", pCMD);
255 
256  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
257  {
258  LOGF_ERROR("Error writing Handshake to TheSkyX TCP server. Result: %d", rc);
259  return false;
260  }
261 
262  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
263  {
264  LOGF_ERROR("Error reading Handshake from TheSkyX TCP server. Result: %d", rc);
265  return false;
266  }
267 
268  if (strcmp(pRES, "1#") != 0)
269  {
270  LOGF_ERROR("Error connecting to TheSky. Result: %s", pRES);
271  return false;
272  }
273 
274  return true;
275 }
276 
277 bool Paramount::getMountRADE()
278 {
279  int rc = 0, nbytes_written = 0, nbytes_read = 0;
280  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
281  double SkyXRA = 0., SkyXDEC = 0.;
282 
283  strncpy(pCMD,
284  "/* Java Script */"
285  "var Out;"
286  "sky6RASCOMTele.GetRaDec();"
287  "Out = String(sky6RASCOMTele.dRa) + ',' + String(sky6RASCOMTele.dDec) + '#';",
288  MAXRBUF);
289 
290  LOGF_DEBUG("CMD: %s", pCMD);
291 
292  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
293  {
294  LOGF_ERROR("Error writing GetRaDec to TheSkyX TCP server. Response: %d", rc);
295  return false;
296  }
297 
298  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
299  {
300  LOGF_ERROR("Error reading GetRaDec from TheSkyX TCP server. Result: %d", rc);
301  return false;
302  }
303 
304  LOGF_DEBUG("RES: %s", pRES);
305 
306  // Read results successfully into temporary values before committing
307  if (sscanf(pRES, "|No error. Error = 0.%lf,%lf#", &SkyXRA, &SkyXDEC) == 2)
308  {
309  currentRA = SkyXRA;
310  currentDEC = SkyXDEC;
311  return true;
312  }
313 
314  LOGF_ERROR("Error reading coordinates. Result: %s", pRES);
315  return false;
316 }
317 
318 INDI::Telescope::TelescopePierSide Paramount::getPierSide()
319 {
320  int rc = 0, nbytes_written = 0, nbytes_read = 0;
321  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
322  int SkyXPierSide = -1;
323 
324  strncpy(pCMD,
325  "/* Java Script */"
326  "var Out;"
327  "sky6RASCOMTele.DoCommand(11, \"Pier Side\");"
328  "Out = sky6RASCOMTele.DoCommandOutput + '#';",
329  MAXRBUF);
330 
331  LOGF_DEBUG("CMD: %s", pCMD);
332 
333  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
334  {
335  LOGF_ERROR("Error writing DoCommand(Pier Side) to TheSkyX TCP server. Result: %d", rc);
336  return PIER_UNKNOWN;
337  }
338 
339  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
340  {
341  LOGF_ERROR("Error reading Pier Side from TheSkyX TCP server. Result: %d", rc);
342  return PIER_UNKNOWN;
343  }
344 
345  LOGF_DEBUG("RES: %s", pRES);
346 
347  if (sscanf(pRES, "|No error. Error = 0.%d#", &SkyXPierSide) == 1)
348  {
349  return SkyXPierSide == 1 ? PIER_WEST : PIER_EAST;
350  }
351 
352  LOGF_ERROR("Error reading Pier Side. Result: %s", pRES);
353  return PIER_UNKNOWN;
354 }
355 
357 {
358  if (isSimulation())
359  {
360  mountSim();
361  return true;
362  }
363 
364  if (TrackState == SCOPE_SLEWING)
365  {
366  // Check if Scope is done slewing
367  if (isSlewComplete())
368  {
370 
371  if (HomeSP.s == IPS_BUSY)
372  {
373  IUResetSwitch(&HomeSP);
374  HomeSP.s = IPS_OK;
375  LOG_INFO("Finding home completed.");
376  }
377  else
378  LOG_INFO("Slew is complete. Tracking...");
379  }
380  }
381  else if (TrackState == SCOPE_PARKING)
382  {
383  if (isTheSkyParked())
384  {
385  SetParked(true);
386  }
387  }
388 
389  if (!getMountRADE())
390  return false;
391 
392  char RAStr[64], DecStr[64];
393 
394  fs_sexa(RAStr, currentRA, 2, 3600);
395  fs_sexa(DecStr, currentDEC, 2, 3600);
396 
397  DEBUGF(DBG_SCOPE, "Current RA: %s Current DEC: %s", RAStr, DecStr);
398 
399  setPierSide(getPierSide());
400 
401  NewRaDec(currentRA, currentDEC);
402  return true;
403 }
404 
405 bool Paramount::Goto(double r, double d)
406 {
407  targetRA = r;
408  targetDEC = d;
409  char RAStr[64], DecStr[64];
410 
411  fs_sexa(RAStr, targetRA, 2, 3600);
412  fs_sexa(DecStr, targetDEC, 2, 3600);
413 
414  char pCMD[MAXRBUF] = {0};
415  snprintf(pCMD, MAXRBUF,
416  "sky6RASCOMTele.Asynchronous = true;"
417  "sky6RASCOMTele.SlewToRaDec(%g, %g,'');",
418  targetRA, targetDEC);
419 
420  if (!sendTheSkyOKCommand(pCMD, "Slewing to target"))
421  return false;
422 
424 
425  LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
426  return true;
427 }
428 
429 bool Paramount::isSlewComplete()
430 {
431  int rc = 0, nbytes_written = 0, nbytes_read = 0;
432  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
433 
434  strncpy(pCMD,
435  "/* Java Script */"
436  "var Out;"
437  "Out = sky6RASCOMTele.IsSlewComplete + '#';",
438  MAXRBUF);
439 
440  LOGF_DEBUG("CMD: %s", pCMD);
441 
442  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
443  {
444  LOGF_ERROR("Error writing IsSlewComplete to TheSkyX TCP server. Result: %d", rc);
445  return false;
446  }
447 
448  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
449  {
450  LOGF_ERROR("Error reading IsSlewComplete from TheSkyX TCP server. Result: %d", rc);
451  return false;
452  }
453 
454  LOGF_DEBUG("RES: %s", pRES);
455 
456  int isComplete = 0;
457  if (sscanf(pRES, "|No error. Error = 0.%d#", &isComplete) == 1)
458  {
459  return isComplete == 1 ? 1 : 0;
460  }
461 
462  LOGF_ERROR("Error reading isSlewComplete. Result: %s", pRES);
463  return false;
464 }
465 
466 bool Paramount::isTheSkyParked()
467 {
468  int rc = 0, nbytes_written = 0, nbytes_read = 0;
469  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
470 
471  strncpy(pCMD,
472  "/* Java Script */"
473  "var Out;"
474  "Out = sky6RASCOMTele.IsParked() + '#';",
475  MAXRBUF);
476 
477  LOGF_DEBUG("CMD: %s", pCMD);
478 
479  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
480  {
481  LOGF_ERROR("Error writing sky6RASCOMTele.IsParked() to TheSkyX TCP server. Result: %d", rc);
482  return false;
483  }
484 
485  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
486  {
487  LOGF_ERROR("Error reading sky6RASCOMTele.IsParked() from TheSkyX TCP server. Result: %d", rc);
488  return false;
489  }
490 
491  LOGF_DEBUG("RES: %s", pRES);
492 
493  if (strcmp(pRES, "|No error. Error = 0.true#") == 0)
494  return true;
495  if (strcmp(pRES, "|No error. Error = 0.false#") == 0)
496  return false;
497 
498  LOGF_ERROR("Error checking for park. Invalid response: %s", pRES);
499  return false;
500 }
501 
502 bool Paramount::isTheSkyTracking()
503 {
504  int rc = 0, nbytes_written = 0, nbytes_read = 0;
505  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
506 
507  strncpy(pCMD,
508  "/* Java Script */"
509  "var Out;"
510  "Out = sky6RASCOMTele.IsTracking + '#';",
511  MAXRBUF);
512 
513  LOGF_DEBUG("CMD: %s", pCMD);
514 
515  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
516  {
517  LOGF_ERROR("Error writing sky6RASCOMTele.IsTracking to TheSkyX TCP server. Result: %d", rc);
518  return false;
519  }
520 
521  if ((rc = tty_read_section(PortFD, pRES, '#', PARAMOUNT_TIMEOUT, &nbytes_read)) != TTY_OK)
522  {
523  LOGF_ERROR("Error reading sky6RASCOMTele.IsTracking from TheSkyX TCP server. Result: %d", rc);
524  return false;
525  }
526 
527  LOGF_DEBUG("RES: %s", pRES);
528 
529  double SkyXTrackRate = 0.;
530  if (sscanf(pRES, "|No error. Error = 0.%lf#", &SkyXTrackRate) == 1)
531  {
532  if (SkyXTrackRate == 0)
533  return false;
534  else if (SkyXTrackRate > 0)
535  return true;
536  }
537 
538  LOGF_ERROR("Error checking for tracking. Invalid response: %s", pRES);
539  return false;
540 }
541 
542 bool Paramount::Sync(double ra, double dec)
543 {
544  char pCMD[MAXRBUF] = {0};
545 
546  snprintf(pCMD, MAXRBUF, "sky6RASCOMTele.Sync(%g, %g,'');", targetRA, targetDEC);
547  if (!sendTheSkyOKCommand(pCMD, "Syncing to target"))
548  return false;
549 
550  currentRA = ra;
551  currentDEC = dec;
552 
553  LOG_INFO("Sync is successful.");
554 
555  EqNP.s = IPS_OK;
556 
557  NewRaDec(currentRA, currentDEC);
558 
559  return true;
560 }
561 
563 {
564  double targetHA = GetAxis1Park();
565  targetRA = range24(get_local_sidereal_time(LocationN[LOCATION_LONGITUDE].value) - targetHA);
566  targetDEC = GetAxis2Park();
567 
568  char pCMD[MAXRBUF] = {0};
569  strncpy(pCMD,
570  "sky6RASCOMTele.Asynchronous = true;"
571  "sky6RASCOMTele.ParkAndDoNotDisconnect();",
572  MAXRBUF);
573 
574  if (!sendTheSkyOKCommand(pCMD, "Parking mount"))
575  return false;
577  LOG_INFO("Parking telescope in progress...");
578 
579  return true;
580 }
581 
583 {
584  char pCMD[MAXRBUF] = {0};
585  strncpy(pCMD, "sky6RASCOMTele.Unpark();", MAXRBUF);
586  if (!sendTheSkyOKCommand(pCMD, "Unparking mount"))
587  return false;
588 
589  // Confirm we unparked
590  if (isTheSkyParked())
591  LOG_ERROR("Could not unpark for some reason.");
592  else
593  SetParked(false);
594 
595  return true;
596 }
597 
598 bool Paramount::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
599 {
600  // first check if it's for our device
601  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
602  {
603  if (strcmp(name, "JOG_RATE") == 0)
604  {
605  IUUpdateNumber(&JogRateNP, values, names, n);
606  JogRateNP.s = IPS_OK;
607  IDSetNumber(&JogRateNP, nullptr);
608  return true;
609  }
610 
611  // Guiding Rate
612  if (strcmp(name, GuideRateNP.name) == 0)
613  {
614  IUUpdateNumber(&GuideRateNP, values, names, n);
615  GuideRateNP.s = IPS_OK;
616  IDSetNumber(&GuideRateNP, nullptr);
617  return true;
618  }
619 
620  if (strcmp(name, GuideNSNP.name) == 0 || strcmp(name, GuideWENP.name) == 0)
621  {
622  processGuiderProperties(name, values, names, n);
623  return true;
624  }
625  }
626 
627  // if we didn't process it, continue up the chain, let somebody else give it a shot
628  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
629 }
630 
631 bool Paramount::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
632 {
633  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
634  {
635  if (!strcmp(HomeSP.name, name))
636  {
637  LOG_INFO("Moving to home position. Please stand by...");
638  if (findHome())
639  {
640  HomeS[0].s = ISS_OFF;
642  HomeSP.s = IPS_OK;
643  LOG_INFO("Mount arrived at home position.");
644  }
645  else
646  {
647  HomeS[0].s = ISS_OFF;
648  HomeSP.s = IPS_ALERT;
649  LOG_ERROR("Failed to go to home position");
650  }
651 
652  IDSetSwitch(&HomeSP, nullptr);
653  return true;
654  }
655  }
656 
657  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
658 }
659 
661 {
662  char pCMD[MAXRBUF] = {0};
663 
664  strncpy(pCMD, "sky6RASCOMTele.Abort();", MAXRBUF);
665  return sendTheSkyOKCommand(pCMD, "Abort mount slew");
666 }
667 
668 bool Paramount::findHome()
669 {
670  char pCMD[MAXRBUF] = {0};
671 
672  strncpy(pCMD, "sky6RASCOMTele.FindHome();"
673  "while(!sky6RASCOMTele.IsSlewComplete) {"
674  "sky6Web.Sleep(1000);}",
675  MAXRBUF);
676  return sendTheSkyOKCommand(pCMD, "Find home", 60);
677 }
678 
679 
681 {
682  if (TrackState == SCOPE_PARKED)
683  {
684  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
685  return false;
686  }
687 
688  int motion = (dir == DIRECTION_NORTH) ? PARAMOUNT_NORTH : PARAMOUNT_SOUTH;
689  //int rate = IUFindOnSwitchIndex(&SlewRateSP);
691 
692  switch (command)
693  {
694  case MOTION_START:
695  if (!isSimulation() && !startOpenLoopMotion(motion, rate))
696  {
697  LOG_ERROR("Error setting N/S motion direction.");
698  return false;
699  }
700  else
701  LOGF_INFO("Moving toward %s.", (motion == PARAMOUNT_NORTH) ? "North" : "South");
702  break;
703 
704  case MOTION_STOP:
705  if (!isSimulation() && !stopOpenLoopMotion())
706  {
707  LOG_ERROR("Error stopping N/S motion.");
708  return false;
709  }
710  else
711  LOGF_INFO("Moving toward %s halted.",
712  (motion == PARAMOUNT_NORTH) ? "North" : "South");
713  break;
714  }
715 
716  return true;
717 }
718 
720 {
721  if (TrackState == SCOPE_PARKED)
722  {
723  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
724  return false;
725  }
726 
727  int motion = (dir == DIRECTION_WEST) ? PARAMOUNT_WEST : PARAMOUNT_EAST;
728  int rate = IUFindOnSwitchIndex(&SlewRateSP);
729 
730  switch (command)
731  {
732  case MOTION_START:
733  if (!isSimulation() && !startOpenLoopMotion(motion, rate))
734  {
735  LOG_ERROR("Error setting W/E motion direction.");
736  return false;
737  }
738  else
739  LOGF_INFO("Moving toward %s.", (motion == PARAMOUNT_WEST) ? "West" : "East");
740  break;
741 
742  case MOTION_STOP:
743  if (!isSimulation() && !stopOpenLoopMotion())
744  {
745  LOG_ERROR("Error stopping W/E motion.");
746  return false;
747  }
748  else
749  LOGF_INFO("Movement toward %s halted.",
750  (motion == PARAMOUNT_WEST) ? "West" : "East");
751  break;
752  }
753 
754  return true;
755 }
756 
757 bool Paramount::startOpenLoopMotion(uint8_t motion, uint16_t rate)
758 {
759  char pCMD[MAXRBUF] = {0};
760 
761  snprintf(pCMD, MAXRBUF, "sky6RASCOMTele.DoCommand(9,'%d|%d');", motion, rate);
762  return sendTheSkyOKCommand(pCMD, "Starting open loop motion");
763 }
764 
765 bool Paramount::stopOpenLoopMotion()
766 {
767  char pCMD[MAXRBUF] = {0};
768 
769  strncpy(pCMD, "sky6RASCOMTele.DoCommand(10,'');", MAXRBUF);
770  return sendTheSkyOKCommand(pCMD, "Stopping open loop motion");
771 }
772 
773 bool Paramount::updateTime(ln_date *utc, double utc_offset)
774 {
775  INDI_UNUSED(utc);
776  INDI_UNUSED(utc_offset);
777  return true;
778 }
779 
781 {
782  char pCMD[MAXRBUF] = {0};
783 
784  strncpy(pCMD, "sky6RASCOMTele.SetParkPosition();", MAXRBUF);
785  if (!sendTheSkyOKCommand(pCMD, "Setting Park Position"))
786  return false;
787 
789  double ha = get_local_hour_angle(lst, currentRA);
790 
791  SetAxis1Park(ha);
792  SetAxis2Park(currentDEC);
793 
794  return true;
795 }
796 
798 {
799  // By default set HA to 0
800  SetAxis1Park(0);
801 
802  // Set DEC to 90 or -90 depending on the hemisphere
803  SetAxis2Park((LocationN[LOCATION_LATITUDE].value > 0) ? 90 : -90);
804 
805  return true;
806 }
807 
808 bool Paramount::SetParkPosition(double Axis1Value, double Axis2Value)
809 {
810  INDI_UNUSED(Axis1Value);
811  INDI_UNUSED(Axis2Value);
812  LOG_ERROR("Setting custom parking position directly is not supported. Slew to the desired "
813  "parking position and click Current.");
814  return false;
815 }
816 
817 void Paramount::mountSim()
818 {
819  static struct timeval ltv
820  {
821  0, 0
822  };
823  struct timeval tv
824  {
825  0, 0
826  };
827  double dt, dx, da_ra = 0, da_dec = 0;
828  int nlocked;
829 
830  /* update elapsed time since last poll, don't presume exactly POLLMS */
831  gettimeofday(&tv, nullptr);
832 
833  if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
834  ltv = tv;
835 
836  dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
837  ltv = tv;
838 
839  if (fabs(targetRA - currentRA) * 15. >= GOTO_LIMIT)
840  da_ra = GOTO_RATE * dt;
841  else if (fabs(targetRA - currentRA) * 15. >= SLEW_LIMIT)
842  da_ra = SLEW_RATE * dt;
843  else
844  da_ra = FINE_SLEW_RATE * dt;
845 
846  if (fabs(targetDEC - currentDEC) >= GOTO_LIMIT)
847  da_dec = GOTO_RATE * dt;
848  else if (fabs(targetDEC - currentDEC) >= SLEW_LIMIT)
849  da_dec = SLEW_RATE * dt;
850  else
851  da_dec = FINE_SLEW_RATE * dt;
852 
853  double motionRate = 0;
854 
855  if (MovementNSSP.s == IPS_BUSY)
856  motionRate = JogRateN[0].value;
857  else if (MovementWESP.s == IPS_BUSY)
858  motionRate = JogRateN[1].value;
859 
860  if (motionRate != 0)
861  {
862  da_ra = motionRate * dt * 0.05;
863  da_dec = motionRate * dt * 0.05;
864 
865  switch (MovementNSSP.s)
866  {
867  case IPS_BUSY:
869  currentDEC += da_dec;
870  else if (MovementNSS[DIRECTION_SOUTH].s == ISS_ON)
871  currentDEC -= da_dec;
872  break;
873 
874  default:
875  break;
876  }
877 
878  switch (MovementWESP.s)
879  {
880  case IPS_BUSY:
882  currentRA += da_ra / 15.;
883  else if (MovementWES[DIRECTION_EAST].s == ISS_ON)
884  currentRA -= da_ra / 15.;
885  break;
886 
887  default:
888  break;
889  }
890 
891  NewRaDec(currentRA, currentDEC);
892  return;
893  }
894 
895  /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
896  switch (TrackState)
897  {
898  case SCOPE_IDLE:
899  /* RA moves at sidereal, Dec stands still */
900  currentRA += (TRACKRATE_SIDEREAL / 3600.0 * dt / 15.);
901  break;
902 
903  case SCOPE_SLEWING:
904  case SCOPE_PARKING:
905  /* slewing - nail it when both within one pulse @ SLEWRATE */
906  nlocked = 0;
907 
908  dx = targetRA - currentRA;
909 
910  // Take shortest path
911  if (fabs(dx) > 12)
912  dx *= -1;
913 
914  if (fabs(dx) <= da_ra)
915  {
916  currentRA = targetRA;
917  nlocked++;
918  }
919  else if (dx > 0)
920  currentRA += da_ra / 15.;
921  else
922  currentRA -= da_ra / 15.;
923 
924  if (currentRA < 0)
925  currentRA += 24;
926  else if (currentRA > 24)
927  currentRA -= 24;
928 
929  dx = targetDEC - currentDEC;
930  if (fabs(dx) <= da_dec)
931  {
932  currentDEC = targetDEC;
933  nlocked++;
934  }
935  else if (dx > 0)
936  currentDEC += da_dec;
937  else
938  currentDEC -= da_dec;
939 
940  if (nlocked == 2)
941  {
942  if (TrackState == SCOPE_SLEWING)
944  else
945  SetParked(true);
946  }
947  break;
948 
949  default:
950  break;
951  }
952 
953  NewRaDec(currentRA, currentDEC);
954 }
955 
956 bool Paramount::sendTheSkyOKCommand(const char *command, const char *errorMessage, uint8_t timeout)
957 {
958  int rc = 0, nbytes_written = 0, nbytes_read = 0;
959  char pCMD[MAXRBUF] = {0}, pRES[MAXRBUF] = {0};
960 
961  snprintf(pCMD, MAXRBUF,
962  "/* Java Script */"
963  "var Out;"
964  "try {"
965  "%s"
966  "Out = 'OK#'; }"
967  "catch (err) {Out = err; }",
968  command);
969 
970  LOGF_DEBUG("CMD: %s", pCMD);
971 
972  tcflush(PortFD, TCIOFLUSH);
973 
974  if ((rc = tty_write_string(PortFD, pCMD, &nbytes_written)) != TTY_OK)
975  {
976  LOGF_ERROR("Error writing sendTheSkyOKCommand to TheSkyX TCP server. Result: $%d", rc);
977  return false;
978  }
979 
980  if ((rc = tty_read_section(PortFD, pRES, '#', timeout, &nbytes_read)) != TTY_OK)
981  {
982  LOGF_ERROR("Error reading sendTheSkyOKCommand from TheSkyX TCP server. Result: %d", rc);
983  return false;
984  }
985 
986  LOGF_DEBUG("RES: %s", pRES);
987 
988  tcflush(PortFD, TCIOFLUSH);
989 
990  if (strcmp("|No error. Error = 0.OK#", pRES) == 0 )
991  return true;
992  else
993  {
994  LOGF_ERROR("sendTheSkyOKCommand Error %s - Invalid response: %s", errorMessage, pRES);
995  return false;
996  }
997 }
998 
1000 {
1001  return GuideNS(static_cast<int>(ms));
1002 }
1003 
1005 {
1006  return GuideNS(-static_cast<int>(ms));
1007 }
1008 
1010 {
1011  return GuideWE(static_cast<int>(ms));
1012 }
1013 
1015 {
1016  return GuideWE(-static_cast<int>(ms));
1017 }
1018 
1020 {
1021  if (TrackState == SCOPE_PARKED)
1022  {
1023  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
1024  return IPS_ALERT;
1025  }
1026 
1027  // Movement in arcseconds
1028  // Send async
1029  double dDec = GuideRateN[DEC_AXIS].value * TRACKRATE_SIDEREAL * ms / 1000.0;
1030  char pCMD[MAXRBUF] = {0};
1031  snprintf(pCMD, MAXRBUF,
1032  "sky6RASCOMTele.Asynchronous = true;"
1033  "sky6DirectGuide.MoveTelescope(%g, %g);", 0., dDec);
1034 
1035  if (!sendTheSkyOKCommand(pCMD, "Guide North-South"))
1036  return IPS_ALERT;
1037 
1038  m_NSTimer.start(ms);
1039 
1040  return IPS_BUSY;
1041 }
1042 
1044 {
1045  if (TrackState == SCOPE_PARKED)
1046  {
1047  LOG_ERROR("Please unpark the mount before issuing any motion commands.");
1048  return IPS_ALERT;
1049  }
1050 
1051  // Movement in arcseconds
1052  // Send async
1053  double dRA = GuideRateN[RA_AXIS].value * TRACKRATE_SIDEREAL * ms / 1000.0;
1054  char pCMD[MAXRBUF] = {0};
1055  snprintf(pCMD, MAXRBUF,
1056  "sky6RASCOMTele.Asynchronous = true;"
1057  "sky6DirectGuide.MoveTelescope(%g, %g);", dRA, 0.);
1058 
1059  if (!sendTheSkyOKCommand(pCMD, "Guide West-East"))
1060  return IPS_ALERT;
1061 
1062  m_WETimer.start(ms);
1063 
1064  return IPS_BUSY;
1065 }
1066 
1067 bool Paramount::setTheSkyTracking(bool enable, bool isSidereal, double raRate, double deRate)
1068 {
1069  int on = enable ? 1 : 0;
1070  int ignore = isSidereal ? 1 : 0;
1071  char pCMD[MAXRBUF] = {0};
1072 
1073  snprintf(pCMD, MAXRBUF, "sky6RASCOMTele.SetTracking(%d, %d, %g, %g);", on, ignore, raRate, deRate);
1074  return sendTheSkyOKCommand(pCMD, "Setting tracking rate");
1075 }
1076 
1077 bool Paramount::SetTrackRate(double raRate, double deRate)
1078 {
1079  return setTheSkyTracking(true, false, raRate, deRate);
1080 }
1081 
1082 bool Paramount::SetTrackMode(uint8_t mode)
1083 {
1084  bool isSidereal = (mode == TRACK_SIDEREAL);
1085  double dRA = 0, dDE = 0;
1086 
1087  if (mode == TRACK_SOLAR)
1088  dRA = TRACKRATE_SOLAR;
1089  else if (mode == TRACK_LUNAR)
1090  dRA = TRACKRATE_LUNAR;
1091  else if (mode == TRACK_CUSTOM)
1092  {
1093  dRA = TrackRateN[RA_AXIS].value;
1094  dDE = TrackRateN[DEC_AXIS].value;
1095  }
1096  return setTheSkyTracking(true, isSidereal, dRA, dDE);
1097 }
1098 
1099 bool Paramount::SetTrackEnabled(bool enabled)
1100 {
1101  // On engaging track, we simply set the current track mode and it will take care of the rest including custom track rates.
1102  if (enabled)
1103  return SetTrackMode(IUFindOnSwitchIndex(&TrackModeSP));
1104  else
1105  // Otherwise, simply switch everything off
1106  return setTheSkyTracking(0, 0, 0., 0.);
1107 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
uint16_t getDriverInterface() const
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
void setTelescopeConnection(const uint8_t &value)
setTelescopeConnection Set telescope connection mode. Child class should call this in the constructor...
double GetAxis2Park() const
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
ISwitchVectorProperty SlewRateSP
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
ISwitch MovementWES[2]
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
INumber ScopeParametersN[4]
INumber TrackRateN[2]
ISwitch MovementNSS[2]
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
INumber LocationN[3]
void setPierSide(TelescopePierSide side)
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
ISwitchVectorProperty MovementWESP
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
void setSingleShot(bool singleShot)
Set whether the timer is a single-shot timer.
Definition: inditimer.cpp:109
void callOnTimeout(const std::function< void()> &callback)
Definition: inditimer.cpp:76
void start()
Starts or restarts the timer with the timeout specified in interval.
Definition: inditimer.cpp:82
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
Definition: paramount.cpp:1099
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: paramount.cpp:598
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: paramount.cpp:164
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
Definition: paramount.cpp:1014
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
Definition: paramount.cpp:999
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: paramount.cpp:107
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
Definition: paramount.cpp:1082
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
Definition: paramount.cpp:1077
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
Definition: paramount.cpp:1009
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
Definition: paramount.cpp:797
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
Definition: paramount.cpp:719
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition: paramount.cpp:542
IPState GuideNS(int32_t ms)
Definition: paramount.cpp:1019
IPState GuideWE(int32_t ms)
Definition: paramount.cpp:1043
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: paramount.cpp:356
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
Definition: paramount.cpp:773
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
Definition: paramount.cpp:405
virtual bool UnPark() override
Unpark the telescope if already parked.
Definition: paramount.cpp:582
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
Definition: paramount.cpp:660
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
Definition: paramount.cpp:780
virtual bool Park() override
Park the telescope to its home position.
Definition: paramount.cpp:562
virtual bool Handshake() override
perform handshake with device to check communication
Definition: paramount.cpp:239
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
Definition: paramount.cpp:680
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
Definition: paramount.cpp:1004
virtual bool SetParkPosition(double Axis1Value, double Axis2Value) override
SetParkPosition Set desired parking position to the supplied value. This ONLY sets the desired park p...
Definition: paramount.cpp:808
virtual const char * getDefaultName() override
Definition: paramount.cpp:102
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: paramount.cpp:631
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
#define currentDEC
Definition: ieq45.cpp:48
#define currentRA
Definition: ieq45.cpp:47
double ra
double dec
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_ATMOST1
Definition: indiapi.h:174
INDI_DIR_WE
Definition: indibasetypes.h:55
@ DIRECTION_EAST
Definition: indibasetypes.h:57
@ DIRECTION_WEST
Definition: indibasetypes.h:56
INDI_DIR_NS
Definition: indibasetypes.h:48
@ DIRECTION_SOUTH
Definition: indibasetypes.h:50
@ DIRECTION_NORTH
Definition: indibasetypes.h:49
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition: indicom.c:1235
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
Definition: indicom.c:141
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition: indicom.c:1293
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
#define TRACKRATE_SOLAR
Definition: indicom.h:61
#define TRACKRATE_SIDEREAL
Definition: indicom.h:55
#define TRACKRATE_LUNAR
Definition: indicom.h:64
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
#define MAXRBUF
Definition: indiserver.cpp:102
#define SLEW_RATE
Definition: paramount.cpp:52
const double slewspeeds[SLEWMODES]
Definition: paramount.cpp:69
#define PARAMOUNT_NORTH
Definition: paramount.cpp:59
#define SLEWMODES
Definition: paramount.cpp:68
#define GOTO_RATE
Definition: paramount.cpp:51
#define FINE_SLEW_RATE
Definition: paramount.cpp:53
#define PARAMOUNT_EAST
Definition: paramount.cpp:61
#define RA_AXIS
Definition: paramount.cpp:64
#define PARAMOUNT_SOUTH
Definition: paramount.cpp:60
#define DEC_AXIS
Definition: paramount.cpp:65
#define SLEW_LIMIT
Definition: paramount.cpp:56
std::unique_ptr< Paramount > paramount_mount(new Paramount())
#define PARAMOUNT_WEST
Definition: paramount.cpp:62
#define PARAMOUNT_TIMEOUT
Definition: paramount.cpp:58
#define GOTO_LIMIT
Definition: paramount.cpp:55
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
Definition: indilogger.cpp:339
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
Definition: indilogger.cpp:72
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371