Instrument Neutral Distributed Interface INDI 2.2.5
lx200basic.cpp
Go to the documentation of this file.
1#if 0
2LX200 Basic Driver
3Copyright (C) 2015 Jasem Mutlaq ([email protected])
4
5This library is free software;
6you can redistribute it and / or
7modify it under the terms of the GNU Lesser General Public
8License as published by the Free Software Foundation;
9either
10version 2.1 of the License, or (at your option) any later version.
11
12This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY;
14without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16Lesser General Public License for more details.
17
18You should have received a copy of the GNU Lesser General Public
19License along with this library;
20if not, write to the Free Software
21Foundation, 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 */
42static 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***************************************************************************************/
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
91
93
95 currentDEC = LocationNP[LOCATION_LATITUDE].getValue() > 0 ? 90 : -90;
96
97 return true;
98}
99
100/**************************************************************************************
101**
102***************************************************************************************/
104{
106
107 if (isConnected())
108 {
110
111 // We don't support NSWE controls
114
115 getBasicData();
116 }
117 else
118 {
120 }
121
122 return true;
123}
124
125/**************************************************************************************
126**
127***************************************************************************************/
129{
130 if (getLX200RA(PortFD, &currentRA) != 0)
131 {
132 LOG_ERROR("Error communication with telescope.");
133 return false;
134 }
135
136 return true;
137}
138
139/**************************************************************************************
140**
141***************************************************************************************/
143{
144 const double dx = targetRA - currentRA;
145 const double dy = targetDEC - currentDEC;
146 return fabs(dx) <= (SlewAccuracyN[0].value / (900.0)) && fabs(dy) <= (SlewAccuracyN[1].value / 60.0);
147}
148
149/**************************************************************************************
150**
151***************************************************************************************/
153{
154 if (!isConnected())
155 return false;
156
157 if (isSimulation())
158 {
159 mountSim();
160 return true;
161 }
162
164 {
166 LOG_ERROR("Error reading RA/DEC.");
167 EqNP.apply();
168 return false;
169 }
170
172 {
173 // Check if LX200 is done slewing
174 if (isSlewComplete())
175 {
177 LOG_INFO("Slew is complete. Tracking...");
178 }
179 }
180
182
183 return true;
184}
185
186/**************************************************************************************
187**
188***************************************************************************************/
189bool LX200Basic::Goto(double r, double d)
190{
191 targetRA = r;
192 targetDEC = d;
193 char RAStr[64] = {0}, DecStr[64] = {0};
194
195 fs_sexa(RAStr, targetRA, 2, 3600);
196 fs_sexa(DecStr, targetDEC, 2, 3600);
197
198 // If moving, let's stop it first.
199 if (EqNP.getState() == IPS_BUSY)
200 {
201 if (!isSimulation() && abortSlew(PortFD) < 0)
202 {
204 LOG_ERROR("Abort slew failed.");
205 AbortSP.apply();
206 return false;
207 }
208
211 LOG_ERROR("Slew aborted.");
212 AbortSP.apply();
213 EqNP.apply();
214
215 // sleep for 100 mseconds
216 usleep(100000);
217 }
218
219 if (!isSimulation())
220 {
222 {
224 LOG_ERROR("Error setting RA/DEC.");
225 EqNP.apply();
226 return false;
227 }
228
229 int err = 0;
230
231 /* Slew reads the '0', that is not the end of the slew */
232 if ((err = Slew(PortFD)))
233 {
235 LOGF_ERROR("Error Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
236 EqNP.apply();
237 slewError(err);
238 return false;
239 }
240 }
241
243 //EqNP.s = IPS_BUSY;
244
245 LOGF_INFO("Slewing to RA: %s - DEC: %s", RAStr, DecStr);
246 return true;
247}
248
249/**************************************************************************************
250**
251***************************************************************************************/
252bool LX200Basic::Sync(double ra, double dec)
253{
254 char syncString[256] = {0};
255
256 if (!isSimulation() && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0))
257 {
259 LOG_ERROR("Error setting RA/DEC. Unable to Sync.");
260 EqNP.apply();
261 return false;
262 }
263
264 if (!isSimulation() && ::Sync(PortFD, syncString) < 0)
265 {
267 LOG_ERROR("Synchronization failed.");
268 EqNP.apply();
269 return false;
270 }
271
272 currentRA = ra;
273 currentDEC = dec;
274
275 LOG_INFO("Synchronization successful.");
276
278
280
281 return true;
282}
283
284/**************************************************************************************
285**
286***************************************************************************************/
287bool LX200Basic::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
288{
289 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
290 {
291 if (!strcmp(name, SlewAccuracyNP.name))
292 {
293 if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
294 return false;
295
297
298 if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
299 IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
300
301 IDSetNumber(&SlewAccuracyNP, nullptr);
302 return true;
303 }
304 }
305
306 return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
307}
308
309/**************************************************************************************
310**
311***************************************************************************************/
313{
314 if (!isSimulation() && abortSlew(PortFD) < 0)
315 {
316 LOG_ERROR("Failed to abort slew.");
317 return false;
318 }
319
322 EqNP.apply();
323
324 LOG_INFO("Slew aborted.");
325 return true;
326}
327
328/**************************************************************************************
329**
330***************************************************************************************/
332{
333 // Make sure short
335
336 // Get current RA/DEC
339
340 EqNP.apply();
341}
342
343/**************************************************************************************
344**
345***************************************************************************************/
347{
348 static struct timeval ltv;
349 struct timeval tv;
350 double dt, da, dx;
351 int nlocked;
352
353 /* update elapsed time since last poll, don't presume exactly POLLMS */
354 gettimeofday(&tv, nullptr);
355
356 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
357 ltv = tv;
358
359 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
360 ltv = tv;
361 da = SLEWRATE * dt;
362
363 /* Process per current state. We check the state of EQUATORIAL_COORDS and act accordingly */
364 switch (TrackState)
365 {
366 case SCOPE_TRACKING:
367 /* RA moves at sidereal, Dec stands still */
368 currentRA += (SIDRATE * dt / 15.);
369 break;
370
371 case SCOPE_SLEWING:
372 /* slewing - nail it when both within one pulse @ SLEWRATE */
373 nlocked = 0;
374
375 dx = targetRA - currentRA;
376
377 if (fabs(dx) <= da)
378 {
380 nlocked++;
381 }
382 else if (dx > 0)
383 currentRA += da / 15.;
384 else
385 currentRA -= da / 15.;
386
387 dx = targetDEC - currentDEC;
388 if (fabs(dx) <= da)
389 {
391 nlocked++;
392 }
393 else if (dx > 0)
394 currentDEC += da;
395 else
396 currentDEC -= da;
397
398 if (nlocked == 2)
399 {
401 }
402
403 break;
404
405 default:
406 break;
407 }
408
410}
411
412/**************************************************************************************
413**
414***************************************************************************************/
415void LX200Basic::slewError(int slewCode)
416{
418
419 if (slewCode == 1)
420 {
421 LOG_INFO("Object below horizon");
422 EqNP.apply();
423 }
424 else if (slewCode == 2)
425 {
426 LOG_INFO("Object below the minimum elevation limit.");
427 EqNP.apply();
428 }
429 else
430 {
431 LOG_INFO("Slew failed.");
432 EqNP.apply();
433 }
434}
435
436/**************************************************************************************
437**
438***************************************************************************************/
440{
443 return true;
444}
bool isConnected() const
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 setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
TelescopeStatus TrackState
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.
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.
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...
bool isSlewComplete()
void getBasicData()
virtual bool Handshake() override
perform handshake with device to check communication
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.
double targetRA
Definition lx200basic.h:56
virtual const char * getDefaultName() override
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.
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
void slewError(int slewCode)
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
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.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
INumberVectorProperty SlewAccuracyNP
Definition lx200basic.h:54
virtual bool ReadScopeStatus() override
Read telescope status.
void mountSim()
virtual bool initProperties() override
Called to initialize basic properties required all the time.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
INDI::PropertySwitch AbortSP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertySwitch MountTypeSP
INDI::PropertySwitch MovementWESP
INDI::PropertyNumber LocationNP
#define SLEWRATE
Definition ieqpro.cpp:35
double ra
double dec
@ ISS_ON
Definition indiapi.h:150
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition indiapi.h:498
@ IP_RW
Definition indiapi.h:184
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
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:130
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sidereal 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:490
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
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:398
#define INDI_UNUSED(x)
Definition indidevapi.h:132
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#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 LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
#define SIDRATE
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)
#define getLX200DEC(fd, x)
#define getLX200RA(fd, x)
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
char name[MAXINDINAME]
Definition indiapi.h:321