Instrument Neutral Distributed Interface INDI  2.0.2
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
36 using namespace INDI::AlignmentSubsystem;
37 
38 // We declare an auto pointer to DSC.
39 std::unique_ptr<DSC> dsc(new DSC());
40 
42 {
43  SetTelescopeCapability(TELESCOPE_CAN_SYNC | TELESCOPE_HAS_LOCATION, 0);
44 }
45 
46 const char *DSC::getDefaultName()
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,
77  ISR_1OFMANY, 0, IPS_IDLE);
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,
83  ISR_NOFMANY, 0, IPS_IDLE);
84 
85  // Offsets applied to raw encoder values to adjust them as necessary
86 #if 0
87  IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_SCALE], "OFFSET_AXIS1_SCALE", "#1 Ticks Scale", "%g", 0, 1e6, 0, 1);
88  IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_OFFSET], "OFFSET_AXIS1_OFFSET", "#1 Ticks Offset", "%g", -1e6, 1e6, 0, 0);
89  IUFillNumber(&EncoderOffsetN[AXIS1_DEGREE_OFFSET], "AXIS1_DEGREE_OFFSET", "#1 Degrees Offset", "%g", -180, 180, 30, 0);
90  IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_SCALE], "OFFSET_AIXS2_SCALE", "#2 Ticks Scale", "%g", 0, 1e6, 0, 1);
91  IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_OFFSET], "OFFSET_AXIS2_OFFSET", "#2 Ticks Offset", "%g", -1e6, 1e6, 0, 0);
92  IUFillNumber(&EncoderOffsetN[AXIS2_DEGREE_OFFSET], "AXIS2_DEGREE_OFFSET", "#2 Degrees Offset", "%g", -180, 180, 30, 0);
93  IUFillNumberVector(&EncoderOffsetNP, EncoderOffsetN, 6, getDeviceName(), "AXIS_OFFSET", "Offsets", AXIS_TAB, IP_RW, 0,
94  IPS_IDLE);
95 #endif
96 
97  // Mount Type
98  IUFillSwitch(&MountTypeS[MOUNT_EQUATORIAL], "MOUNT_EQUATORIAL", "Equatorial", ISS_ON);
99  IUFillSwitch(&MountTypeS[MOUNT_ALTAZ], "MOUNT_ALTAZ", "AltAz", ISS_OFF);
100  IUFillSwitchVector(&MountTypeSP, MountTypeS, 2, getDeviceName(), "MOUNT_TYPE", "Mount Type", MAIN_CONTROL_TAB,
101  IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
102 
103  // Simulation encoder values
104  IUFillNumber(&SimEncoderN[AXIS1_ENCODER], "AXIS1_ENCODER", "Axis 1", "%0.f", -1e6, 1e6, 0, 0);
105  IUFillNumber(&SimEncoderN[AXIS2_ENCODER], "AXIS2_ENCODER", "Axis 2", "%0.f", -1e6, 1e6, 0, 0);
106  IUFillNumberVector(&SimEncoderNP, SimEncoderN, 2, getDeviceName(), "SIM_ENCODER", "Sim Encoders", MAIN_CONTROL_TAB,
107  IP_RW, 0, IPS_IDLE);
108 
109  addAuxControls();
110 
111  InitAlignmentProperties(this);
112 
113  return true;
114 }
115 
117 {
119 
120  if (isConnected())
121  {
122  defineProperty(&EncoderNP);
123  defineProperty(&AxisSettingsNP);
124  defineProperty(&AxisRangeSP);
125  defineProperty(&ReverseSP);
126  //defineProperty(&EncoderOffsetNP);
127  defineProperty(&MountTypeSP);
128 
129  if (isSimulation())
130  defineProperty(&SimEncoderNP);
131 
132  SetAlignmentSubsystemActive(true);
133  }
134  else
135  {
136  deleteProperty(EncoderNP.name);
137  deleteProperty(AxisSettingsNP.name);
138  deleteProperty(AxisRangeSP.name);
139  deleteProperty(ReverseSP.name);
140  //deleteProperty(EncoderOffsetNP.name);
141  deleteProperty(MountTypeSP.name);
142 
143  if (isSimulation())
144  deleteProperty(SimEncoderNP.name);
145  }
146 
147  return true;
148 }
149 
150 bool DSC::saveConfigItems(FILE *fp)
151 {
153 
154  IUSaveConfigNumber(fp, &AxisSettingsNP);
155  //IUSaveConfigNumber(fp, &EncoderOffsetNP);
156  IUSaveConfigSwitch(fp, &AxisRangeSP);
157  IUSaveConfigSwitch(fp, &ReverseSP);
158  IUSaveConfigSwitch(fp, &MountTypeSP);
159 
160  return true;
161 }
162 
163 bool DSC::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
164 {
165  ProcessAlignmentTextProperties(this, name, texts, names, n);
166 
167  return INDI::Telescope::ISNewText(dev, name, texts, names, n);
168 }
169 
170 bool DSC::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
171 {
172  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
173  {
174  if (strcmp(name, AxisSettingsNP.name) == 0)
175  {
176  IUUpdateNumber(&AxisSettingsNP, values, names, n);
177  AxisSettingsNP.s = IPS_OK;
178  IDSetNumber(&AxisSettingsNP, nullptr);
179  return true;
180  }
181 
182  /*if(strcmp(name,EncoderOffsetNP.name) == 0)
183  {
184  IUUpdateNumber(&EncoderOffsetNP, values, names, n);
185  EncoderOffsetNP.s = IPS_OK;
186  IDSetNumber(&EncoderOffsetNP, nullptr);
187  return true;
188  }*/
189 
190  if (strcmp(name, SimEncoderNP.name) == 0)
191  {
192  IUUpdateNumber(&SimEncoderNP, values, names, n);
193  SimEncoderNP.s = IPS_OK;
194  IDSetNumber(&SimEncoderNP, nullptr);
195  return true;
196  }
197 
198  ProcessAlignmentNumberProperties(this, name, values, names, n);
199  }
200 
201  return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
202 }
203 
204 bool DSC::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
205 {
206  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
207  {
208  if (strcmp(name, ReverseSP.name) == 0)
209  {
210  IUUpdateSwitch(&ReverseSP, states, names, n);
211  ReverseSP.s = IPS_OK;
212  IDSetSwitch(&ReverseSP, nullptr);
213  return true;
214  }
215 
216  if (strcmp(name, MountTypeSP.name) == 0)
217  {
218  IUUpdateSwitch(&MountTypeSP, states, names, n);
219  MountTypeSP.s = IPS_OK;
220  IDSetSwitch(&MountTypeSP, nullptr);
221  return true;
222  }
223 
224  if (strcmp(name, AxisRangeSP.name) == 0)
225  {
226  IUUpdateSwitch(&AxisRangeSP, states, names, n);
227  AxisRangeSP.s = IPS_OK;
228 
229  if (AxisRangeS[AXIS_FULL_STEP].s == ISS_ON)
230  {
231  LOGF_INFO("Axis range is from 0 to %.f", AxisSettingsN[AXIS1_TICKS].value);
232  }
233  else
234  {
235  LOGF_INFO("Axis range is from -%.f to %.f",
236  AxisSettingsN[AXIS1_TICKS].value / 2, AxisSettingsN[AXIS1_TICKS].value / 2);
237  }
238  IDSetSwitch(&AxisRangeSP, nullptr);
239  return true;
240  }
241 
242  ProcessAlignmentSwitchProperties(this, name, states, names, n);
243  }
244 
245  return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
246 }
247 
249 {
250  return true;
251 }
252 
254 {
255  // Send 'Q'
256  char CR[1] = { 0x51 };
257  // Response
258  char response[16] = { 0 };
259  int rc = 0, nbytes_read = 0, nbytes_written = 0;
260 
261  LOGF_DEBUG("CMD: %#02X", CR[0]);
262 
263  if (isSimulation())
264  {
265  snprintf(response, 16, "%06.f\t%06.f", SimEncoderN[AXIS1_ENCODER].value, SimEncoderN[AXIS2_ENCODER].value);
266  }
267  else
268  {
269  tcflush(PortFD, TCIFLUSH);
270 
271  if ((rc = tty_write(PortFD, CR, 1, &nbytes_written)) != TTY_OK)
272  {
273  char errmsg[256];
274  tty_error_msg(rc, errmsg, 256);
275  LOGF_ERROR("Error writing to device %s (%d)", errmsg, rc);
276  return false;
277  }
278 
279  // Read until we encounter a CR
280  if ((rc = tty_read_section(PortFD, response, 0x0D, DSC_TIMEOUT, &nbytes_read)) != TTY_OK)
281  {
282  // if we read enough, let's try to process, otherwise throw error
283  // 6 characters for each number
284  if (nbytes_read < 12)
285  {
286  char errmsg[256];
287  tty_error_msg(rc, errmsg, 256);
288  LOGF_ERROR("Error reading from device %s (%d)", errmsg, rc);
289  return false;
290  }
291  }
292  }
293 
294  LOGF_DEBUG("RES: %s", response);
295 
296  double Axis1Encoder = 0, Axis2Encoder = 0;
297  std::regex rgx(R"((\+?\-?\d+)\s(\+?\-?\d+))");
298  std::smatch match;
299  std::string input(response);
300 
301  if (std::regex_search(input, match, rgx))
302  {
303  Axis1Encoder = atof(match.str(1).c_str());
304  Axis2Encoder = atof(match.str(2).c_str());
305  }
306  else
307  {
308  LOGF_ERROR("Error processing response: %s", response);
309  EncoderNP.s = IPS_ALERT;
310  IDSetNumber(&EncoderNP, nullptr);
311  return false;
312  }
313 
314  LOGF_DEBUG("Raw Axis encoders. Axis1: %g Axis2: %g", Axis1Encoder, Axis2Encoder);
315 
316  EncoderN[AXIS1_RAW_ENCODER].value = Axis1Encoder;
317  EncoderN[AXIS2_RAW_ENCODER].value = Axis2Encoder;
318 
319  // Convert Half Step to Full Step
320  if (AxisRangeS[AXIS_HALF_STEP].s == ISS_ON)
321  {
322  if (Axis1Encoder < 0)
323  Axis1Encoder += AxisSettingsN[AXIS1_TICKS].value;
324 
325  if (Axis2Encoder < 0)
326  Axis2Encoder += AxisSettingsN[AXIS2_TICKS].value;
327  }
328 
329  // Calculate reverse values
330  double Axis1 = Axis1Encoder;
331  if (ReverseS[AXIS1_ENCODER].s == ISS_ON)
332  Axis1 = AxisSettingsN[AXIS1_TICKS].value - Axis1;
333 
334 #if 0
335  if (Axis1Diff < 0)
336  Axis1Diff += AxisSettingsN[AXIS1_TICKS].value;
337  else if (Axis1Diff > AxisSettingsN[AXIS1_TICKS].value)
338  Axis1Diff -= AxisSettingsN[AXIS1_TICKS].value;
339 #endif
340 
341  double Axis2 = Axis2Encoder;
342  if (ReverseS[AXIS2_ENCODER].s == ISS_ON)
343  Axis2 = AxisSettingsN[AXIS2_TICKS].value - Axis2;
344 
345  LOGF_DEBUG("Axis encoders after reverse. Axis1: %g Axis2: %g", Axis1, Axis2);
346 
347  // Apply raw offsets
348 
349  // It seems having encoder offsets like this is confusing for users
350  //Axis1 = (Axis1 * EncoderOffsetN[OFFSET_AXIS1_SCALE].value + EncoderOffsetN[OFFSET_AXIS1_OFFSET].value);
351  //Axis2 = (Axis2 * EncoderOffsetN[OFFSET_AXIS2_SCALE].value + EncoderOffsetN[OFFSET_AXIS2_OFFSET].value);
352 
353  //LOGF_DEBUG("Axis encoders after raw offsets. Axis1: %g Axis2: %g", Axis1, Axis2);
354 
355  EncoderN[AXIS1_ENCODER].value = Axis1;
356  EncoderN[AXIS2_ENCODER].value = Axis2;
357  EncoderNP.s = IPS_OK;
358  IDSetNumber(&EncoderNP, nullptr);
359 
360  double Axis1Degrees = (Axis1 / AxisSettingsN[AXIS1_TICKS].value * 360.0) + AxisSettingsN[AXIS1_DEGREE_OFFSET].value;
361  double Axis2Degrees = (Axis2 / AxisSettingsN[AXIS2_TICKS].value * 360.0) + AxisSettingsN[AXIS2_DEGREE_OFFSET].value;
362 
363  Axis1Degrees = range360(Axis1Degrees);
364  Axis2Degrees = range360(Axis2Degrees);
365 
366  // Adjust for LST
367  double LST = get_local_sidereal_time(m_Location.longitude);
368 
369  // Final aligned equatorial position
371 
372  // Now we proceed depending on mount type
373  if (MountTypeS[MOUNT_EQUATORIAL].s == ISS_ON)
374  {
375  encoderEquatorialCoordinates.rightascension = Axis1Degrees / 15.0;
376 
377  encoderEquatorialCoordinates.rightascension += LST;
378  encoderEquatorialCoordinates.rightascension = range24(encoderEquatorialCoordinates.rightascension);
379 
380  encoderEquatorialCoordinates.declination = rangeDec(Axis2Degrees);
381 
382  // Do alignment
383  eq = TelescopeEquatorialToSky();
384  }
385  else
386  {
387  encoderHorizontalCoordinates.azimuth = Axis1Degrees;
388  encoderHorizontalCoordinates.azimuth += 180;
389  encoderHorizontalCoordinates.azimuth = range360(encoderHorizontalCoordinates.azimuth);
390 
391  encoderHorizontalCoordinates.altitude = Axis2Degrees;
392 
393  // Do alignment
394  eq = TelescopeHorizontalToSky();
395 
396  char AzStr[64], AltStr[64];
397  fs_sexa(AzStr, Axis1Degrees, 2, 3600);
398  fs_sexa(AltStr, Axis2Degrees, 2, 3600);
399  LOGF_DEBUG("Current Az: %s Current Alt: %s", AzStr, AltStr);
400  }
401 
402  // Now feed the rest of the system with corrected data
403  NewRaDec(eq.rightascension, eq.declination);
404  return true;
405 }
406 
407 bool DSC::Sync(double ra, double dec)
408 {
409  AlignmentDatabaseEntry NewEntry;
410  INDI::IEquatorialCoordinates RaDec { 0, 0 };
412 
413  if (MountTypeS[MOUNT_EQUATORIAL].s == ISS_ON)
414  {
415  double LST = get_local_sidereal_time(m_Location.longitude);
416  RaDec.rightascension = range24(LST - encoderEquatorialCoordinates.rightascension);
417  RaDec.declination = encoderEquatorialCoordinates.declination;
418  }
419  else
420  {
421  AltAz.azimuth = encoderHorizontalCoordinates.azimuth;
422  AltAz.altitude = encoderHorizontalCoordinates.altitude;
423  }
424 
425  NewEntry.ObservationJulianDate = ln_get_julian_from_sys();
426  NewEntry.RightAscension = ra;
427  NewEntry.Declination = dec;
428 
429  if (MountTypeS[MOUNT_EQUATORIAL].s == ISS_ON)
430  NewEntry.TelescopeDirection = TelescopeDirectionVectorFromLocalHourAngleDeclination(RaDec);
431  else
432  NewEntry.TelescopeDirection = TelescopeDirectionVectorFromAltitudeAzimuth(AltAz);
433 
434  NewEntry.PrivateDataSize = 0;
435  DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "New sync point Date %lf RA %lf DEC %lf TDV(x %lf y %lf z %lf)",
436  NewEntry.ObservationJulianDate, NewEntry.RightAscension, NewEntry.Declination, NewEntry.TelescopeDirection.x,
437  NewEntry.TelescopeDirection.y, NewEntry.TelescopeDirection.z);
438 
439  if (!CheckForDuplicateSyncPoint(NewEntry))
440  {
441  GetAlignmentDatabase().push_back(NewEntry);
442 
443  // Tell the client about size change
444  UpdateSize();
445 
446  // Tell the math plugin to reinitialise
447  Initialise(this);
448 
449  return true;
450  }
451 
452  return false;
453 }
454 
455 INDI::IEquatorialCoordinates DSC::TelescopeEquatorialToSky()
456 {
457  double RightAscension, Declination;
459 
460  if (GetAlignmentDatabase().size() > 1)
461  {
463 
464  /* and here we convert from ra/dec to hour angle / dec before calling alignment stuff */
465  double lha, lst;
466  lst = get_local_sidereal_time(LocationN[LOCATION_LONGITUDE].value);
467  lha = get_local_hour_angle(lst, encoderEquatorialCoordinates.rightascension);
468  // convert lha to degrees
469  lha = lha * 360 / 24;
470  eq.rightascension = lha;
471  eq.declination = encoderEquatorialCoordinates.declination;
472  TDV = TelescopeDirectionVectorFromLocalHourAngleDeclination(eq);
473 
474  if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
475  {
476  RightAscension = encoderEquatorialCoordinates.rightascension;
477  Declination = encoderEquatorialCoordinates.declination;
478  }
479  }
480  else
481  {
482  // With less than 2 align points
483  // Just return raw data
484  RightAscension = encoderEquatorialCoordinates.rightascension;
485  Declination = encoderEquatorialCoordinates.declination;
486  }
487 
488  eq.rightascension = RightAscension;
489  eq.declination = Declination;
490  return eq;
491 }
492 
493 INDI::IEquatorialCoordinates DSC::TelescopeHorizontalToSky()
494 {
496  TelescopeDirectionVector TDV = TelescopeDirectionVectorFromAltitudeAzimuth(encoderHorizontalCoordinates);
497  double RightAscension, Declination;
498 
499  if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
500  {
501  INDI::IEquatorialCoordinates EquatorialCoordinates {0, 0};
502  TelescopeDirectionVector RotatedTDV(TDV);
503 
504  switch (GetApproximateMountAlignment())
505  {
506  case ZENITH:
507  break;
508 
510  // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 minus
511  // the (positive)observatory latitude. The vector itself is rotated clockwise
512  RotatedTDV.RotateAroundY(90.0 - m_Location.latitude);
513  AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
514  break;
515 
517  // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 plus
518  // the (negative)observatory latitude. The vector itself is rotated anticlockwise
519  RotatedTDV.RotateAroundY(-90.0 - m_Location.latitude);
520  AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
521  break;
522  }
523 
524  INDI::HorizontalToEquatorial(&encoderHorizontalCoordinates, &m_Location, ln_get_julian_from_sys(), &EquatorialCoordinates);
525  RightAscension = EquatorialCoordinates.rightascension;
526  Declination = EquatorialCoordinates.declination;
527  }
528 
529  eq.rightascension = RightAscension;
530  eq.declination = Declination;
531  return eq;
532 }
533 
534 bool DSC::updateLocation(double latitude, double longitude, double elevation)
535 {
536  UpdateLocation(latitude, longitude, elevation);
537  return true;
538 }
539 
540 void DSC::simulationTriggered(bool enable)
541 {
542  if (!isConnected())
543  return;
544 
545  if (enable)
546  {
547  defineProperty(&SimEncoderNP);
548  }
549  else
550  {
551  deleteProperty(SimEncoderNP.name);
552  }
553 }
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:150
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: dsc.cpp:204
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:407
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: dsc.cpp:253
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:534
virtual bool Handshake() override
perform handshake with device to check communication
Definition: dsc.cpp:248
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: dsc.cpp:163
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: dsc.cpp:170
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: dsc.cpp:116
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
Definition: dsc.cpp:540
DSC()
Definition: dsc.cpp:41
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.
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.
#define DSC_TIMEOUT
Definition: dsc.cpp:32
std::unique_ptr< DSC > dsc(new DSC())
#define AXIS_TAB
Definition: dsc.cpp:33
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
@ IP_RO
Definition: indiapi.h:184
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_NOFMANY
Definition: indiapi.h:175
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
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition: indicom.c:1235
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition: indicom.c:1245
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
Definition: indicom.c:1255
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
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 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
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
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 LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
INumber eq[]
Definition: intelliscope.c:54
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:156
const char * getDeviceName()
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 nomalised direction vector (direction cosines)
Definition: Common.h:69