Instrument Neutral Distributed Interface INDI  2.0.2
lx200basic.cpp
Go to the documentation of this file.
1 #if 0
2 LX200 Basic Driver
3 Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 
5 This library is free software;
6 you can redistribute it and / or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation;
9 either
10 version 2.1 of the License, or (at your option) any later version.
11 
12 This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY;
14 without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library;
20 if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
22 
23 #endif
24 
25 #include "lx200basic.h"
26 
27 #include "indicom.h"
28 #include "lx200driver.h"
29 
30 #include <libnova/sidereal_time.h>
31 
32 #include <cmath>
33 #include <memory>
34 #include <cstring>
35 #include <unistd.h>
36 
37 /* Simulation Parameters */
38 #define SLEWRATE 1 /* slew rate, degrees/s */
39 #define SIDRATE 0.004178 /* sidereal rate, degrees/s */
40 
41 /* Our telescope auto pointer */
42 static std::unique_ptr<LX200Basic> telescope(new LX200Basic());
43 
44 /**************************************************************************************
45 ** LX200 Basic constructor
46 ***************************************************************************************/
48 {
49  setVersion(2, 1);
50 
51  DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE");
52 
54 
55  LOG_DEBUG("Initializing from LX200 Basic device...");
56 }
57 
58 /**************************************************************************************
59 **
60 ***************************************************************************************/
61 void LX200Basic::debugTriggered(bool enable)
62 {
63  INDI_UNUSED(enable);
65 }
66 
67 /**************************************************************************************
68 **
69 ***************************************************************************************/
71 {
72  return "LX200 Basic";
73 }
74 
75 /**************************************************************************************
76 **
77 ***************************************************************************************/
79 {
80  /* Make sure to init parent properties first */
82 
83  // Slew threshold
84  IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0);
85  IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
88 
90 
92  currentDEC = LocationN[LOCATION_LATITUDE].value > 0 ? 90 : -90;
93 
94  return true;
95 }
96 
97 /**************************************************************************************
98 **
99 ***************************************************************************************/
101 {
103 
104  if (isConnected())
105  {
107 
108  // We don't support NSWE controls
111 
112  getBasicData();
113  }
114  else
115  {
117  }
118 
119  return true;
120 }
121 
122 /**************************************************************************************
123 **
124 ***************************************************************************************/
126 {
127  if (getLX200RA(PortFD, &currentRA) != 0)
128  {
129  LOG_ERROR("Error communication with telescope.");
130  return false;
131  }
132 
133  return true;
134 }
135 
136 /**************************************************************************************
137 **
138 ***************************************************************************************/
140 {
141  const double dx = targetRA - currentRA;
142  const double dy = targetDEC - currentDEC;
143  return fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0);
144 }
145 
146 /**************************************************************************************
147 **
148 ***************************************************************************************/
150 {
151  if (!isConnected())
152  return false;
153 
154  if (isSimulation())
155  {
156  mountSim();
157  return true;
158  }
159 
161  {
162  EqNP.s = IPS_ALERT;
163  IDSetNumber(&EqNP, "Error reading RA/DEC.");
164  return false;
165  }
166 
167  if (TrackState == SCOPE_SLEWING)
168  {
169  // Check if LX200 is done slewing
170  if (isSlewComplete())
171  {
173  LOG_INFO("Slew is complete. Tracking...");
174  }
175  }
176 
178 
179  return true;
180 }
181 
182 /**************************************************************************************
183 **
184 ***************************************************************************************/
185 bool LX200Basic::Goto(double r, double d)
186 {
187  targetRA = r;
188  targetDEC = d;
189  char RAStr[64] = {0}, DecStr[64] = {0};
190 
191  fs_sexa(RAStr, targetRA, 2, 3600);
192  fs_sexa(DecStr, targetDEC, 2, 3600);
193 
194  // If moving, let's stop it first.
195  if (EqNP.s == IPS_BUSY)
196  {
197  if (!isSimulation() && abortSlew(PortFD) < 0)
198  {
199  AbortSP.s = IPS_ALERT;
200  IDSetSwitch(&AbortSP, "Abort slew failed.");
201  return false;
202  }
203 
204  AbortSP.s = IPS_OK;
205  EqNP.s = IPS_IDLE;
206  IDSetSwitch(&AbortSP, "Slew aborted.");
207  IDSetNumber(&EqNP, nullptr);
208 
209  // sleep for 100 mseconds
210  usleep(100000);
211  }
212 
213  if (!isSimulation())
214  {
216  {
217  EqNP.s = IPS_ALERT;
218  IDSetNumber(&EqNP, "Error setting RA/DEC.");
219  return false;
220  }
221 
222  int err = 0;
223 
224  /* Slew reads the '0', that is not the end of the slew */
225  if ((err = Slew(PortFD)))
226  {
227  EqNP.s = IPS_ALERT;
228  IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
229  slewError(err);
230  return false;
231  }
232  }
233 
235  //EqNP.s = IPS_BUSY;
236 
237  LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
238  return true;
239 }
240 
241 /**************************************************************************************
242 **
243 ***************************************************************************************/
244 bool LX200Basic::Sync(double ra, double dec)
245 {
246  char syncString[256] = {0};
247 
248  if (!isSimulation() && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0))
249  {
250  EqNP.s = IPS_ALERT;
251  IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync.");
252  return false;
253  }
254 
255  if (!isSimulation() && ::Sync(PortFD, syncString) < 0)
256  {
257  EqNP.s = IPS_ALERT;
258  IDSetNumber(&EqNP, "Synchronization failed.");
259  return false;
260  }
261 
262  currentRA = ra;
263  currentDEC = dec;
264 
265  LOG_INFO("Synchronization successful.");
266 
267  EqNP.s = IPS_OK;
268 
270 
271  return true;
272 }
273 
274 /**************************************************************************************
275 **
276 ***************************************************************************************/
277 bool LX200Basic::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
278 {
279  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
280  {
281  if (!strcmp(name, SlewAccuracyNP.name))
282  {
283  if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
284  return false;
285 
287 
288  if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
289  IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
290 
291  IDSetNumber(&SlewAccuracyNP, nullptr);
292  return true;
293  }
294  }
295 
296  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
297 }
298 
299 /**************************************************************************************
300 **
301 ***************************************************************************************/
303 {
304  if (!isSimulation() && abortSlew(PortFD) < 0)
305  {
306  LOG_ERROR("Failed to abort slew.");
307  return false;
308  }
309 
310  EqNP.s = IPS_IDLE;
312  IDSetNumber(&EqNP, nullptr);
313 
314  LOG_INFO("Slew aborted.");
315  return true;
316 }
317 
318 /**************************************************************************************
319 **
320 ***************************************************************************************/
322 {
323  // Make sure short
325 
326  // Get current RA/DEC
329 
330  IDSetNumber(&EqNP, nullptr);
331 }
332 
333 /**************************************************************************************
334 **
335 ***************************************************************************************/
337 {
338  static struct timeval ltv;
339  struct timeval tv;
340  double dt, da, dx;
341  int nlocked;
342 
343  /* update elapsed time since last poll, don't presume exactly POLLMS */
344  gettimeofday(&tv, nullptr);
345 
346  if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
347  ltv = tv;
348 
349  dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
350  ltv = tv;
351  da = SLEWRATE * dt;
352 
353  /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
354  switch (TrackState)
355  {
356  case SCOPE_TRACKING:
357  /* RA moves at sidereal, Dec stands still */
358  currentRA += (SIDRATE * dt / 15.);
359  break;
360 
361  case SCOPE_SLEWING:
362  /* slewing - nail it when both within one pulse @ SLEWRATE */
363  nlocked = 0;
364 
365  dx = targetRA - currentRA;
366 
367  if (fabs(dx) <= da)
368  {
370  nlocked++;
371  }
372  else if (dx > 0)
373  currentRA += da / 15.;
374  else
375  currentRA -= da / 15.;
376 
377  dx = targetDEC - currentDEC;
378  if (fabs(dx) <= da)
379  {
381  nlocked++;
382  }
383  else if (dx > 0)
384  currentDEC += da;
385  else
386  currentDEC -= da;
387 
388  if (nlocked == 2)
389  {
391  }
392 
393  break;
394 
395  default:
396  break;
397  }
398 
400 }
401 
402 /**************************************************************************************
403 **
404 ***************************************************************************************/
405 void LX200Basic::slewError(int slewCode)
406 {
407  EqNP.s = IPS_ALERT;
408 
409  if (slewCode == 1)
410  IDSetNumber(&EqNP, "Object below horizon.");
411  else if (slewCode == 2)
412  IDSetNumber(&EqNP, "Object below the minimum elevation limit.");
413  else
414  IDSetNumber(&EqNP, "Slew failed.");
415 }
416 
417 /**************************************************************************************
418 **
419 ***************************************************************************************/
421 {
424  return true;
425 }
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.
TelescopeStatus TrackState
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
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.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
INumberVectorProperty EqNP
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
INumber LocationN[3]
ISwitchVectorProperty MovementWESP
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: lx200basic.cpp:420
bool isSlewComplete()
Definition: lx200basic.cpp:139
void getBasicData()
Definition: lx200basic.cpp:321
virtual bool Handshake() override
perform handshake with device to check communication
Definition: lx200basic.cpp:125
double currentRA
Definition: lx200basic.h:57
double currentDEC
Definition: lx200basic.h:57
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: lx200basic.cpp:100
double targetRA
Definition: lx200basic.h:56
virtual const char * getDefaultName() override
Definition: lx200basic.cpp:70
INumber SlewAccuracyN[2]
Definition: lx200basic.h:53
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: lx200basic.cpp:277
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition: lx200basic.cpp:244
void slewError(int slewCode)
Definition: lx200basic.cpp:405
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
Definition: lx200basic.cpp:302
uint32_t DBG_SCOPE
Definition: lx200basic.h:58
double targetDEC
Definition: lx200basic.h:56
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
Definition: lx200basic.cpp:185
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
Definition: lx200basic.cpp:61
INumberVectorProperty SlewAccuracyNP
Definition: lx200basic.h:54
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: lx200basic.cpp:149
void mountSim()
Definition: lx200basic.cpp:336
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: lx200basic.cpp:78
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
double ra
double dec
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition: indiapi.h:500
@ IP_RW
Definition: indiapi.h:186
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
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
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
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
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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
#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 LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define SIDRATE
Definition: lx200basic.cpp:39
#define SLEWRATE
Definition: lx200basic.cpp:38
int setObjectRA(int fd, double ra, bool addSpace)
int setObjectDEC(int fd, double dec, bool addSpace)
int checkLX200EquatorialFormat(int fd)
int abortSlew(int fd)
int Slew(int fd)
void setLX200Debug(const char *deviceName, unsigned int debug_level)
Definition: lx200driver.cpp:58
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
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