Instrument Neutral Distributed Interface INDI 2.2.5
dsc.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3
4 It just gets the encoder position and outputs current coordinates.
5 Calibratoin and syncing not supported yet.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License version 2 as published by the Free Software Foundation.
10 .
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15 .
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*******************************************************************************/
21
22#include "dsc.h"
23
24#include "indicom.h"
25
26#include <cstring>
27#include <memory>
28#include <regex>
29#include <termios.h>
30#include <unistd.h>
31
32#define DSC_TIMEOUT 2
33#define AXIS_TAB "Axis Settings"
34
35#include <alignment/DriverCommon.h> // For DBG_ALIGNMENT
36using namespace INDI::AlignmentSubsystem;
37
38// We declare an auto pointer to DSC.
39std::unique_ptr<DSC> dsc(new DSC());
40
45
47{
48 return (const char *)"Digital Setting Circle";
49}
50
52{
54
55 // Raw encoder values
56 IUFillNumber(&EncoderN[AXIS1_ENCODER], "AXIS1_ENCODER", "Axis 1", "%0.f", 0, 1e6, 0, 0);
57 IUFillNumber(&EncoderN[AXIS2_ENCODER], "AXIS2_ENCODER", "Axis 2", "%0.f", 0, 1e6, 0, 0);
58 IUFillNumber(&EncoderN[AXIS1_RAW_ENCODER], "AXIS1_RAW_ENCODER", "RAW Axis 1", "%0.f", -1e6, 1e6, 0, 0);
59 IUFillNumber(&EncoderN[AXIS2_RAW_ENCODER], "AXIS2_RAW_ENCODER", "RAW Axis 2", "%0.f", -1e6, 1e6, 0, 0);
60 IUFillNumberVector(&EncoderNP, EncoderN, 4, getDeviceName(), "DCS_ENCODER", "Encoders", MAIN_CONTROL_TAB, IP_RO, 0,
61 IPS_IDLE);
62
63 // Encoder Settings
64 IUFillNumber(&AxisSettingsN[AXIS1_TICKS], "AXIS1_TICKS", "#1 ticks/rev", "%g", 256, 1e6, 0, 4096);
65 IUFillNumber(&AxisSettingsN[AXIS1_DEGREE_OFFSET], "AXIS1_DEGREE_OFFSET", "#1 Degrees Offset", "%g", -180, 180, 30,
66 0);
67 IUFillNumber(&AxisSettingsN[AXIS2_TICKS], "AXIS2_TICKS", "#2 ticks/rev", "%g", 256, 1e6, 0, 4096);
68 IUFillNumber(&AxisSettingsN[AXIS2_DEGREE_OFFSET], "AXIS2_DEGREE_OFFSET", "#2 Degrees Offset", "%g", -180, 180, 30,
69 0);
70 IUFillNumberVector(&AxisSettingsNP, AxisSettingsN, 4, getDeviceName(), "AXIS_SETTINGS", "Axis Resolution", AXIS_TAB,
71 IP_RW, 0, IPS_IDLE);
72
73 // Axis Range
74 IUFillSwitch(&AxisRangeS[AXIS_FULL_STEP], "AXIS_FULL_STEP", "Full Step", ISS_ON);
75 IUFillSwitch(&AxisRangeS[AXIS_HALF_STEP], "AXIS_HALF_STEP", "Half Step", ISS_OFF);
76 IUFillSwitchVector(&AxisRangeSP, AxisRangeS, 2, getDeviceName(), "AXIS_RANGE", "Axis Range", AXIS_TAB, IP_RW,
78
79 // Reverse Encoder Direction
80 IUFillSwitch(&ReverseS[AXIS1_ENCODER], "AXIS1_REVERSE", "Axis 1", ISS_OFF);
81 IUFillSwitch(&ReverseS[AXIS2_ENCODER], "AXIS2_REVERSE", "Axis 2", ISS_OFF);
82 IUFillSwitchVector(&ReverseSP, ReverseS, 2, getDeviceName(), "AXIS_REVERSE", "Reverse", AXIS_TAB, IP_RW,
84
85
86 MountTypeSP.fill(getDeviceName(), "TELESCOPE_MOUNT_TYPE", "Mount Type", MOTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
89
90 // Offsets applied to raw encoder values to adjust them as necessary
91#if 0
92 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_SCALE], "OFFSET_AXIS1_SCALE", "#1 Ticks Scale", "%g", 0, 1e6, 0, 1);
93 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_OFFSET], "OFFSET_AXIS1_OFFSET", "#1 Ticks Offset", "%g", -1e6, 1e6, 0, 0);
94 IUFillNumber(&EncoderOffsetN[AXIS1_DEGREE_OFFSET], "AXIS1_DEGREE_OFFSET", "#1 Degrees Offset", "%g", -180, 180, 30, 0);
95 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_SCALE], "OFFSET_AIXS2_SCALE", "#2 Ticks Scale", "%g", 0, 1e6, 0, 1);
96 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_OFFSET], "OFFSET_AXIS2_OFFSET", "#2 Ticks Offset", "%g", -1e6, 1e6, 0, 0);
97 IUFillNumber(&EncoderOffsetN[AXIS2_DEGREE_OFFSET], "AXIS2_DEGREE_OFFSET", "#2 Degrees Offset", "%g", -180, 180, 30, 0);
98 IUFillNumberVector(&EncoderOffsetNP, EncoderOffsetN, 6, getDeviceName(), "AXIS_OFFSET", "Offsets", AXIS_TAB, IP_RW, 0,
99 IPS_IDLE);
100#endif
101
102 // Simulation encoder values
103 IUFillNumber(&SimEncoderN[AXIS1_ENCODER], "AXIS1_ENCODER", "Axis 1", "%0.f", -1e6, 1e6, 0, 0);
104 IUFillNumber(&SimEncoderN[AXIS2_ENCODER], "AXIS2_ENCODER", "Axis 2", "%0.f", -1e6, 1e6, 0, 0);
105 IUFillNumberVector(&SimEncoderNP, SimEncoderN, 2, getDeviceName(), "SIM_ENCODER", "Sim Encoders", MAIN_CONTROL_TAB,
106 IP_RW, 0, IPS_IDLE);
107
109
111
112 return true;
113}
114
116{
118
119 if (isConnected())
120 {
121 defineProperty(&EncoderNP);
122 defineProperty(&AxisSettingsNP);
123 defineProperty(&AxisRangeSP);
124 defineProperty(&ReverseSP);
125 //defineProperty(&EncoderOffsetNP);
126
127 if (isSimulation())
128 defineProperty(&SimEncoderNP);
129
131 }
132 else
133 {
134 deleteProperty(EncoderNP.name);
135 deleteProperty(AxisSettingsNP.name);
136 deleteProperty(AxisRangeSP.name);
137 deleteProperty(ReverseSP.name);
138 //deleteProperty(EncoderOffsetNP.name);
139
140 if (isSimulation())
141 deleteProperty(SimEncoderNP.name);
142 }
143
144 return true;
145}
146
148{
150
151 IUSaveConfigNumber(fp, &AxisSettingsNP);
152 //IUSaveConfigNumber(fp, &EncoderOffsetNP);
153 IUSaveConfigSwitch(fp, &AxisRangeSP);
154 IUSaveConfigSwitch(fp, &ReverseSP);
155 MountTypeSP.save(fp);
156
157 return true;
158}
159
160bool DSC::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
161{
162 ProcessAlignmentTextProperties(this, name, texts, names, n);
163
164 return INDI::Telescope::ISNewText(dev, name, texts, names, n);
165}
166
167bool DSC::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
168{
169 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
170 {
171 if (strcmp(name, AxisSettingsNP.name) == 0)
172 {
173 IUUpdateNumber(&AxisSettingsNP, values, names, n);
174 AxisSettingsNP.s = IPS_OK;
175 IDSetNumber(&AxisSettingsNP, nullptr);
176 return true;
177 }
178
179 /*if(strcmp(name,EncoderOffsetNP.name) == 0)
180 {
181 IUUpdateNumber(&EncoderOffsetNP, values, names, n);
182 EncoderOffsetNP.s = IPS_OK;
183 IDSetNumber(&EncoderOffsetNP, nullptr);
184 return true;
185 }*/
186
187 if (strcmp(name, SimEncoderNP.name) == 0)
188 {
189 IUUpdateNumber(&SimEncoderNP, values, names, n);
190 SimEncoderNP.s = IPS_OK;
191 IDSetNumber(&SimEncoderNP, nullptr);
192 return true;
193 }
194
195 ProcessAlignmentNumberProperties(this, name, values, names, n);
196 }
197
198 return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
199}
200
201bool DSC::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
202{
203 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
204 {
205 if (strcmp(name, ReverseSP.name) == 0)
206 {
207 IUUpdateSwitch(&ReverseSP, states, names, n);
208 ReverseSP.s = IPS_OK;
209 IDSetSwitch(&ReverseSP, nullptr);
210 return true;
211 }
212
213 if (MountTypeSP.isNameMatch(name))
214 {
215 MountTypeSP.update(states, names, n);
218 return true;
219 }
220
221 if (strcmp(name, AxisRangeSP.name) == 0)
222 {
223 IUUpdateSwitch(&AxisRangeSP, states, names, n);
224 AxisRangeSP.s = IPS_OK;
225
226 if (AxisRangeS[AXIS_FULL_STEP].s == ISS_ON)
227 {
228 LOGF_INFO("Axis range is from 0 to %.f", AxisSettingsN[AXIS1_TICKS].value);
229 }
230 else
231 {
232 LOGF_INFO("Axis range is from -%.f to %.f",
233 AxisSettingsN[AXIS1_TICKS].value / 2, AxisSettingsN[AXIS1_TICKS].value / 2);
234 }
235 IDSetSwitch(&AxisRangeSP, nullptr);
236 return true;
237 }
238
239 ProcessAlignmentSwitchProperties(this, name, states, names, n);
240 }
241
242 return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
243}
244
246{
247 return true;
248}
249
251{
252 // Send 'Q'
253 char CR[1] = { 0x51 };
254 // Response
255 char response[18] = { 0 };
256 int rc = 0, nbytes_read = 0, nbytes_written = 0;
257
258 LOGF_DEBUG("CMD: %#02X", CR[0]);
259
260 if (isSimulation())
261 {
262 snprintf(response, 18, "%06.f\t%06.f", SimEncoderN[AXIS1_ENCODER].value, SimEncoderN[AXIS2_ENCODER].value);
263 }
264 else
265 {
266 tcflush(PortFD, TCIFLUSH);
267
268 if ((rc = tty_write(PortFD, CR, 1, &nbytes_written)) != TTY_OK)
269 {
270 char errmsg[256];
271 tty_error_msg(rc, errmsg, 256);
272 LOGF_ERROR("Error writing to device %s (%d)", errmsg, rc);
273 return false;
274 }
275
276 // Read until we encounter a CR
277 if ((rc = tty_read_section(PortFD, response, 0x0D, DSC_TIMEOUT, &nbytes_read)) != TTY_OK)
278 {
279 // if we read enough, let's try to process, otherwise throw error
280 // 6 characters for each number
281 if (nbytes_read < 12)
282 {
283 char errmsg[256];
284 tty_error_msg(rc, errmsg, 256);
285 LOGF_ERROR("Error reading from device %s (%d)", errmsg, rc);
286 return false;
287 }
288 }
289 }
290
291 LOGF_DEBUG("RES: %s", response);
292
293 double Axis1Encoder = 0, Axis2Encoder = 0;
294 std::regex rgx(R"((\+?\-?\d+)\s(\+?\-?\d+))");
295 std::smatch match;
296 std::string input(response);
297
298 if (std::regex_search(input, match, rgx))
299 {
300 Axis1Encoder = atof(match.str(1).c_str());
301 Axis2Encoder = atof(match.str(2).c_str());
302 }
303 else
304 {
305 LOGF_ERROR("Error processing response: %s", response);
306 EncoderNP.s = IPS_ALERT;
307 IDSetNumber(&EncoderNP, nullptr);
308 return false;
309 }
310
311 LOGF_DEBUG("Raw Axis encoders. Axis1: %g Axis2: %g", Axis1Encoder, Axis2Encoder);
312
313 EncoderN[AXIS1_RAW_ENCODER].value = Axis1Encoder;
314 EncoderN[AXIS2_RAW_ENCODER].value = Axis2Encoder;
315
316 // Convert Half Step to Full Step
317 if (AxisRangeS[AXIS_HALF_STEP].s == ISS_ON)
318 {
319 if (Axis1Encoder < 0)
320 Axis1Encoder += AxisSettingsN[AXIS1_TICKS].value;
321
322 if (Axis2Encoder < 0)
323 Axis2Encoder += AxisSettingsN[AXIS2_TICKS].value;
324 }
325
326 // Calculate reverse values
327 double Axis1 = Axis1Encoder;
328 if (ReverseS[AXIS1_ENCODER].s == ISS_ON)
329 Axis1 = AxisSettingsN[AXIS1_TICKS].value - Axis1;
330
331#if 0
332 if (Axis1Diff < 0)
333 Axis1Diff += AxisSettingsN[AXIS1_TICKS].value;
334 else if (Axis1Diff > AxisSettingsN[AXIS1_TICKS].value)
335 Axis1Diff -= AxisSettingsN[AXIS1_TICKS].value;
336#endif
337
338 double Axis2 = Axis2Encoder;
339 if (ReverseS[AXIS2_ENCODER].s == ISS_ON)
340 Axis2 = AxisSettingsN[AXIS2_TICKS].value - Axis2;
341
342 LOGF_DEBUG("Axis encoders after reverse. Axis1: %g Axis2: %g", Axis1, Axis2);
343
344 // Apply raw offsets
345
346 // It seems having encoder offsets like this is confusing for users
347 //Axis1 = (Axis1 * EncoderOffsetN[OFFSET_AXIS1_SCALE].value + EncoderOffsetN[OFFSET_AXIS1_OFFSET].value);
348 //Axis2 = (Axis2 * EncoderOffsetN[OFFSET_AXIS2_SCALE].value + EncoderOffsetN[OFFSET_AXIS2_OFFSET].value);
349
350 //LOGF_DEBUG("Axis encoders after raw offsets. Axis1: %g Axis2: %g", Axis1, Axis2);
351
352 EncoderN[AXIS1_ENCODER].value = Axis1;
353 EncoderN[AXIS2_ENCODER].value = Axis2;
354 EncoderNP.s = IPS_OK;
355 IDSetNumber(&EncoderNP, nullptr);
356
357 double Axis1Degrees = (Axis1 / AxisSettingsN[AXIS1_TICKS].value * 360.0) + AxisSettingsN[AXIS1_DEGREE_OFFSET].value;
358 double Axis2Degrees = (Axis2 / AxisSettingsN[AXIS2_TICKS].value * 360.0) + AxisSettingsN[AXIS2_DEGREE_OFFSET].value;
359
360 Axis1Degrees = range360(Axis1Degrees);
361 Axis2Degrees = range360(Axis2Degrees);
362
363 // Adjust for LST
365
366 // Final aligned equatorial position
368
369 // Now we proceed depending on mount type
371 {
372 encoderEquatorialCoordinates.rightascension = Axis1Degrees / 15.0;
373
374 encoderEquatorialCoordinates.rightascension += LST;
375 encoderEquatorialCoordinates.rightascension = range24(encoderEquatorialCoordinates.rightascension);
376
377 encoderEquatorialCoordinates.declination = rangeDec(Axis2Degrees);
378
379 // Do alignment
380 eq = TelescopeEquatorialToSky();
381 }
382 else
383 {
384 encoderHorizontalCoordinates.azimuth = Axis1Degrees;
385 encoderHorizontalCoordinates.azimuth += 180;
386 encoderHorizontalCoordinates.azimuth = range360(encoderHorizontalCoordinates.azimuth);
387
388 encoderHorizontalCoordinates.altitude = Axis2Degrees;
389
390 // Do alignment
391 eq = TelescopeHorizontalToSky();
392
393 char AzStr[64], AltStr[64];
394 fs_sexa(AzStr, Axis1Degrees, 2, 3600);
395 fs_sexa(AltStr, Axis2Degrees, 2, 3600);
396 LOGF_DEBUG("Current Az: %s Current Alt: %s", AzStr, AltStr);
397 }
398
399 // Now feed the rest of the system with corrected data
400 NewRaDec(eq.rightascension, eq.declination);
401 return true;
402}
403
404bool DSC::Sync(double ra, double dec)
405{
406 AlignmentDatabaseEntry NewEntry;
407 INDI::IEquatorialCoordinates RaDec { 0, 0 };
408 INDI::IHorizontalCoordinates AltAz { 0, 0 };
409
410 if (MountTypeSP[MOUNT_EQ_GEM].getState() == ISS_ON)
411 {
413 RaDec.rightascension = range24(LST - encoderEquatorialCoordinates.rightascension);
414 RaDec.declination = encoderEquatorialCoordinates.declination;
415 }
416 else
417 {
418 AltAz.azimuth = encoderHorizontalCoordinates.azimuth;
419 AltAz.altitude = encoderHorizontalCoordinates.altitude;
420 }
421
422 NewEntry.ObservationJulianDate = ln_get_julian_from_sys();
423 NewEntry.RightAscension = ra;
424 NewEntry.Declination = dec;
425
426 if (MountTypeSP[MOUNT_EQ_GEM].getState() == ISS_ON)
428 else
430
431 NewEntry.PrivateDataSize = 0;
432 DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "New sync point Date %lf RA %lf DEC %lf TDV(x %lf y %lf z %lf)",
433 NewEntry.ObservationJulianDate, NewEntry.RightAscension, NewEntry.Declination, NewEntry.TelescopeDirection.x,
434 NewEntry.TelescopeDirection.y, NewEntry.TelescopeDirection.z);
435
436 if (!CheckForDuplicateSyncPoint(NewEntry))
437 {
438 GetAlignmentDatabase().push_back(NewEntry);
439
440 // Tell the client about size change
441 UpdateSize();
442
443 // Tell the math plugin to reinitialise
444 Initialise(this);
445
446 return true;
447 }
448
449 return false;
450}
451
452INDI::IEquatorialCoordinates DSC::TelescopeEquatorialToSky()
453{
454 double RightAscension, Declination;
456
457 if (GetAlignmentDatabase().size() > 1)
458 {
460
461 /* and here we convert from ra/dec to hour angle / dec before calling alignment stuff */
462 double lha, lst;
464 lha = get_local_hour_angle(lst, encoderEquatorialCoordinates.rightascension);
465 // convert lha to degrees
466 lha = lha * 360 / 24;
467 eq.rightascension = lha;
468 eq.declination = encoderEquatorialCoordinates.declination;
470
471 if (!TransformTelescopeToCelestialJD(TDV, RightAscension, Declination, ln_get_julian_from_sys()))
472 {
473 RightAscension = encoderEquatorialCoordinates.rightascension;
474 Declination = encoderEquatorialCoordinates.declination;
475 }
476 }
477 else
478 {
479 // With less than 2 align points
480 // Just return raw data
481 RightAscension = encoderEquatorialCoordinates.rightascension;
482 Declination = encoderEquatorialCoordinates.declination;
483 }
484
485 eq.rightascension = RightAscension;
486 eq.declination = Declination;
487 return eq;
488}
489
490INDI::IEquatorialCoordinates DSC::TelescopeHorizontalToSky()
491{
494 double RightAscension, Declination;
495
496 if (!TransformTelescopeToCelestialJD(TDV, RightAscension, Declination, ln_get_julian_from_sys()))
497 {
498 INDI::IEquatorialCoordinates EquatorialCoordinates {0, 0};
499 TelescopeDirectionVector RotatedTDV(TDV);
500
502 {
503 case ZENITH:
504 break;
505
507 // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 minus
508 // the (positive)observatory latitude. The vector itself is rotated clockwise
509 RotatedTDV.RotateAroundY(90.0 - m_Location.latitude);
510 AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
511 break;
512
514 // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 plus
515 // the (negative)observatory latitude. The vector itself is rotated anticlockwise
516 RotatedTDV.RotateAroundY(-90.0 - m_Location.latitude);
517 AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
518 break;
519 }
520
521 INDI::HorizontalToEquatorial(&encoderHorizontalCoordinates, &m_Location, ln_get_julian_from_sys(), &EquatorialCoordinates);
522 RightAscension = EquatorialCoordinates.rightascension;
523 Declination = EquatorialCoordinates.declination;
524 }
525
526 eq.rightascension = RightAscension;
527 eq.declination = Declination;
528 return eq;
529}
530
531bool DSC::updateLocation(double latitude, double longitude, double elevation)
532{
533 UpdateLocation(latitude, longitude, elevation);
534 return true;
535}
536
538{
539 if (!isConnected())
540 return;
541
542 if (enable)
543 {
544 defineProperty(&SimEncoderNP);
545 }
546 else
547 {
548 deleteProperty(SimEncoderNP.name);
549 }
550}
Definition dsc.h:32
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition dsc.cpp:147
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition dsc.cpp:201
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
Definition dsc.cpp:404
virtual bool ReadScopeStatus() override
Read telescope status.
Definition dsc.cpp:250
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition dsc.cpp:51
virtual const char * getDefaultName() override
Definition dsc.cpp:46
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
Definition dsc.cpp:531
virtual bool Handshake() override
perform handshake with device to check communication
Definition dsc.cpp:245
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition dsc.cpp:160
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition dsc.cpp:167
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition dsc.cpp:115
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
Definition dsc.cpp:537
DSC()
Definition dsc.cpp:41
void ProcessAlignmentNumberProperties(Telescope *pTelescope, const char *name, double values[], char *names[], int n)
Call this function from within the ISNewNumber processing path. The function will handle any alignmen...
void ProcessAlignmentSwitchProperties(Telescope *pTelescope, const char *name, ISState *states, char *names[], int n)
Call this function from within the ISNewSwitch processing path. The function will handle any alignmen...
void InitAlignmentProperties(Telescope *pTelescope)
Initialize alignment subsystem properties. It is recommended to call this function within initPropert...
void ProcessAlignmentTextProperties(Telescope *pTelescope, const char *name, char *texts[], char *names[], int n)
Call this function from within the ISNewText processing path. The function will handle any alignment ...
bool CheckForDuplicateSyncPoint(const AlignmentDatabaseEntry &CandidateEntry, double Tolerance=0.1) const
Check if a entry already exists in the database.
AlignmentDatabaseType & GetAlignmentDatabase()
Get a reference to the in memory database.
void UpdateLocation(double latitude, double longitude, double elevation)
Call this function from within the updateLocation processing path.
void UpdateSize()
Call this function when the number of entries in the database changes.
bool TransformTelescopeToCelestialJD(const TelescopeDirectionVector &ApparentTelescopeDirectionVector, double &RightAscension, double &Declination, double JulianDate)
TransformTelescopeToCelestialJD Transforms Mount Coords to Celestial (Sky) Coordinates.
bool Initialise(InMemoryDatabase *pInMemoryDatabase)
Initialise or re-initialise the math plugin. Re-reading the in memory database as necessary.
MountAlignment_t GetApproximateMountAlignment()
Get the approximate alignment of the mount.
void SetAlignmentSubsystemActive(bool enable)
SetAlignmentSubsystemActive Enable or Disable alignment subsystem.
const TelescopeDirectionVector TelescopeDirectionVectorFromAltitudeAzimuth(INDI::IHorizontalCoordinates HorizontalCoordinates)
Calculates a normalised direction vector from the supplied altitude and azimuth.
const TelescopeDirectionVector TelescopeDirectionVectorFromLocalHourAngleDeclination(INDI::IEquatorialCoordinates EquatorialCoordinates)
Calculates a telescope direction vector from the supplied local hour angle and declination.
void AltitudeAzimuthFromTelescopeDirectionVector(const TelescopeDirectionVector TelescopeDirectionVector, INDI::IHorizontalCoordinates &HorizontalCoordinates)
Calculates an altitude and azimuth from the supplied normalised direction vector and declination.
bool isConnected() const
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
void save(FILE *f) const
save Save property to configuration file.
bool isNameMatch(const char *otherName) const
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
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 ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
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.
IGeographicCoordinates m_Location
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 ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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 DSC_TIMEOUT
Definition dsc.cpp:32
#define AXIS_TAB
Definition dsc.cpp:33
std::unique_ptr< DSC > dsc(new DSC())
INDI::PropertySwitch MountTypeSP
INDI::PropertyNumber LocationNP
double ra
double dec
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
@ ISR_NOFMANY
Definition indiapi.h:173
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:653
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition indicom.c:1311
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition indicom.c:1321
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
Definition indicom.c:1341
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
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
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition indicom.c:1379
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sidereal time given longitude and system clock.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
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 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:376
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
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:453
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, 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 LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define DEBUGF(priority, msg,...)
Definition indilogger.h:57
#define getDeviceName
INumber eq[]
Namespace to encapsulate the INDI Alignment Subsystem classes. For more information see "INDI Alignme...
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
Definition libastro.cpp:161
Entry in the in memory alignment database.
Definition Common.h:152
double RightAscension
Right ascension in decimal hours. N.B. libnova works in decimal degrees so conversion is always neede...
Definition Common.h:190
TelescopeDirectionVector TelescopeDirection
Normalised vector giving telescope pointing direction. This is referred to elsewhere as the "apparent...
Definition Common.h:197
double Declination
Declination in decimal degrees.
Definition Common.h:193
int PrivateDataSize
This size in bytes of any private data.
Definition Common.h:203
Holds a normalised direction vector (direction cosines)
Definition Common.h:69
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369