Instrument Neutral Distributed Interface INDI  2.0.2
lx200am5.cpp
Go to the documentation of this file.
1 /*
2  ZWO AM5 INDI driver
3 
4  Copyright (C) 2022 Jasem Mutlaq
5 
6  This library is free software; 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; either
9  version 2.1 of the License, or (at your option) any later version.
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  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "lx200am5.h"
22 
24 #include "lx200driver.h"
25 #include "indicom.h"
26 
27 #include <libnova/transform.h>
28 
29 #include <cmath>
30 #include <cstring>
31 #include <stdio.h>
32 #include <termios.h>
33 #include <unistd.h>
34 #include <regex>
35 
37 {
38  setVersion(1, 0);
39 
41 
50  SLEW_MODES);
51 }
52 
54 {
56 
59 
60  tcpConnection->setDefaultHost("192.168.4.1");
64 
68 
69  // Mount Type
70  int mountType = Equatorial;
71  IUGetConfigOnSwitchIndex(getDeviceName(), "MOUNT_TYPE", &mountType);
72  MountTypeSP[Azimuth].fill("Azimuth", "Azimuth", mountType == Azimuth ? ISS_ON : ISS_OFF);
73  MountTypeSP[Equatorial].fill("Equatorial", "Equatorial", mountType == Equatorial ? ISS_ON : ISS_OFF);
74  MountTypeSP.fill(getDeviceName(), "MOUNT_TYPE", "Mount Type", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
75 
76  if (mountType == Equatorial)
78 
79  // Slew Rates
80  strncpy(SlewRateS[0].label, "0.25x", MAXINDILABEL);
81  strncpy(SlewRateS[1].label, "0.50x", MAXINDILABEL);
82  strncpy(SlewRateS[2].label, "1x", MAXINDILABEL);
83  strncpy(SlewRateS[3].label, "2x", MAXINDILABEL);
84  strncpy(SlewRateS[4].label, "4x", MAXINDILABEL);
85  strncpy(SlewRateS[5].label, "8x", MAXINDILABEL);
86  strncpy(SlewRateS[6].label, "20x", MAXINDILABEL);
87  strncpy(SlewRateS[7].label, "60x", MAXINDILABEL);
88  strncpy(SlewRateS[8].label, "720x", MAXINDILABEL);
89  strncpy(SlewRateS[9].label, "1440x", MAXINDILABEL);
91  // 1440x is the default
92  SlewRateS[9].s = ISS_ON;
93 
94  // Home/Zero position
95  HomeSP[0].fill("GO", "Go", ISS_OFF);
96  HomeSP.fill(getDeviceName(), "GO_HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
97 
98  // Guide Rate
99  GuideRateNP[0].fill("RATE", "Rate", "%.2f", 0.1, 0.9, 0.1, 0.5);
100  GuideRateNP.fill(getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 60, IPS_IDLE);
101 
102  // Buzzer
103  BuzzerSP[Off].fill("OFF", "Off", ISS_OFF);
104  BuzzerSP[Low].fill("LOW", "Low", ISS_OFF);
105  BuzzerSP[High].fill("HIGH", "High", ISS_ON);
106  BuzzerSP.fill(getDeviceName(), "BUZZER", "Buzzer", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
107 
108  return true;
109 }
110 
115 {
117 
118  if (isConnected())
119  {
120  setup();
121 
122  defineProperty(HomeSP);
123  defineProperty(GuideRateNP);
124  defineProperty(BuzzerSP);
125 
126  }
127  else
128  {
129  deleteProperty(HomeSP);
130  deleteProperty(GuideRateNP);
131  deleteProperty(BuzzerSP);
132  }
133 
134  return true;
135 }
136 
141 {
142  return "ZWO AM5";
143 }
144 
149 {
150  LOG_DEBUG("Checking AM5 connection...");
151 
152  double targetRA = 0;
153  for (int i = 0; i < 2; i++)
154  {
155  if (getLX200RA(PortFD, &targetRA) == 0)
156  return true;
157 
158  const struct timespec ms250_delay = {.tv_sec = 0, .tv_nsec = 250000000};
159  nanosleep(&ms250_delay, NULL);
160  }
161 
162  return false;
163 }
164 
168 void LX200AM5::setup()
169 {
170  // Mount Type
171  // MountTypeSP.setState(setMountType(MountTypeSP.findOnSwitchIndex()) ? IPS_OK : IPS_ALERT);
172  // MountTypeSP.apply();
173 
174  if (InitPark())
175  {
176  // If loading parking data is successful, we just set the default parking values.
177  SetAxis1ParkDefault(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
179  }
180  else
181  {
182  // Otherwise, we set all parking data to default in case no parking data is found.
183  SetAxis1Park(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
185  SetAxis1ParkDefault(LocationN[LOCATION_LATITUDE].value >= 0 ? 0 : 180);
187  }
188 
189  getMountType();
190  getTrackMode();
191  getGuideRate();
192  getBuzzer();
193 
194 }
195 
199 bool LX200AM5::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
200 {
201  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
202  {
203  // Mount Type
204  if (MountTypeSP.isNameMatch(name))
205  {
206  int previousType = MountTypeSP.findOnSwitchIndex();
207  MountTypeSP.update(states, names, n);
208  IPState state = IPS_OK;
209  // Only update if already connected.
210  if (isConnected())
211  {
212  auto targetType = MountTypeSP.findOnSwitchIndex();
213  state = setMountType(targetType) ? IPS_OK : IPS_ALERT;
214  if (state == IPS_OK && previousType != targetType)
215  LOG_WARN("You must restart mount for change to take effect.");
216  }
217  MountTypeSP.setState(state);
218  MountTypeSP.apply();
219  return true;
220  }
221 
222  // Home
223  if (HomeSP.isNameMatch(name))
224  {
225  if (HomeSP.getState() != IPS_BUSY)
226  {
227  HomeSP[0].setState(ISS_ON);
228  HomeSP.setState(goHome() ? IPS_BUSY : IPS_ALERT);
229  LOG_INFO("Homing in progress...");
230  }
231  HomeSP.apply();
232  return true;
233  }
234  }
235 
236  return LX200Generic::ISNewSwitch(dev, name, states, names, n);
237 }
238 
242 bool LX200AM5::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
243 {
244  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
245  {
246  if (GuideRateNP.isNameMatch(name))
247  {
248  GuideRateNP.update(values, names, n);
249  GuideRateNP.setState(setGuideRate(GuideRateNP[0].getValue()) ? IPS_OK : IPS_ALERT);
250  GuideRateNP.apply();
251  return true;
252  }
253  }
254 
255  return LX200Generic::ISNewNumber(dev, name, values, names, n);
256 }
257 
261 bool LX200AM5::setMountType(int type)
262 {
263  return sendCommand((type == Azimuth) ? ":AA#" : ":AP#");
264 }
265 
269 bool LX200AM5::getMountType()
270 {
271  char response[DRIVER_LEN] = {0};
272  if (sendCommand(":GU#", response))
273  {
274  MountTypeSP.reset();
275  MountTypeSP[Azimuth].setState(strchr(response, 'Z') ? ISS_ON : ISS_OFF);
276  MountTypeSP[Equatorial].setState(strchr(response, 'G') ? ISS_ON : ISS_OFF);
277  MountTypeSP.setState(IPS_OK);
278  return true;
279  }
280  else
281  {
282  MountTypeSP.setState(IPS_ALERT);
283  return true;
284  }
285 }
286 
290 bool LX200AM5::SetSlewRate(int index)
291 {
292  char command[DRIVER_LEN] = {0};
293  snprintf(command, DRIVER_LEN, ":R%d#", index);
294  return sendCommand(command);
295 }
296 
297 
298 
302 bool LX200AM5::setGuideRate(double value)
303 {
304  char command[DRIVER_LEN] = {0};
305  snprintf(command, DRIVER_LEN, ":Rg%.2f", value);
306  return sendCommand(command);
307 }
308 
312 bool LX200AM5::getGuideRate()
313 {
314  char response[DRIVER_LEN] = {0};
315  if (sendCommand(":Ggr#", response))
316  {
317  float rate = 0;
318  int result = sscanf(response, "%f", &rate);
319  if (result == 1)
320  {
321  GuideRateNP[0].setValue(rate);
322  return true;
323  }
324  }
325 
326  GuideRateNP.setState(IPS_ALERT);
327  return false;
328 
329 }
330 
334 bool LX200AM5::getTrackMode()
335 {
336  char response[DRIVER_LEN] = {0};
337  if (sendCommand(":GT#", response))
338  {
340  auto onIndex = response[0] - 0x30;
341  TrackModeS[onIndex].s = ISS_ON;
342  return true;
343  }
344 
346  return false;
347 
348 }
349 
353 bool LX200AM5::setBuzzer(int value)
354 {
355  char command[DRIVER_LEN] = {0};
356  snprintf(command, DRIVER_LEN, ":SBu%d", value);
357  return sendCommand(command);
358 }
359 
363 bool LX200AM5::getBuzzer()
364 {
365  char response[DRIVER_LEN] = {0};
366  if (sendCommand(":GBu#", response))
367  {
368  BuzzerSP.reset();
369  auto onIndex = response[0] - 0x30;
370  BuzzerSP[onIndex].setState(ISS_ON);
371  BuzzerSP.setState(IPS_OK);
372  return true;
373  }
374  else
375  {
376  BuzzerSP.setState(IPS_ALERT);
377  return true;
378  }
379 }
380 
384 bool LX200AM5::setUTCOffset(double offset)
385 {
386  int h {0}, m {0}, s {0};
387  char command[DRIVER_LEN] = {0};
388  offset *= -1;
389  getSexComponents(offset, &h, &m, &s);
390 
391  snprintf(command, DRIVER_LEN, ":SG%c%02d:%02d#", offset >= 0 ? '+' : '-', std::abs(h), m);
392  return setStandardProcedure(PortFD, command) == 0;
393 }
394 
395 bool LX200AM5::setLocalDate(uint8_t days, uint8_t months, uint16_t years)
396 {
397  char command[DRIVER_LEN] = {0};
398  snprintf(command, DRIVER_LEN, ":SC%02d/%02d/%02d#", months, days, years % 100);
399  return setStandardProcedure(PortFD, command) == 0;
400 }
401 
405 bool LX200AM5::SetTrackEnabled(bool enabled)
406 {
407  char response[DRIVER_LEN] = {0};
408  bool rc = sendCommand(enabled ? ":Te#" : ":Td#", response, 4, 1);
409  return rc && response[0] == '1';
410 }
411 
415 bool LX200AM5::isTracking()
416 {
417  char response[DRIVER_LEN] = {0};
418  bool rc = sendCommand(":GAT#", response);
419  return rc && response[0] == '1';
420 }
421 
425 bool LX200AM5::goHome()
426 {
427  return sendCommand(":hC#");
428 }
429 
433 bool LX200AM5::updateLocation(double latitude, double longitude, double elevation)
434 {
435  INDI_UNUSED(elevation);
436  int d{0}, m{0}, s{0};
437 
438  // JM 2021-04-10: MUST convert from INDI longitude to standard longitude.
439  // DO NOT REMOVE
440  if (longitude > 180)
441  longitude = longitude - 360;
442 
443  char command[DRIVER_LEN] = {0};
444  // Reverse as per Meade way
445  longitude *= -1;
446  getSexComponents(longitude, &d, &m, &s);
447  snprintf(command, DRIVER_LEN, ":Sg%c%03d*%02d:%02d#", longitude >= 0 ? '+' : '-', std::abs(d), m, s);
448  if (setStandardProcedure(PortFD, command) < 0)
449  {
450  LOG_ERROR("Error setting site longitude coordinates");
451  return false;
452  }
453 
454  getSexComponents(latitude, &d, &m, &s);
455  snprintf(command, DRIVER_LEN, ":St%c%02d*%02d:%02d#", latitude >= 0 ? '+' : '-', std::abs(d), m, s);
456  if (setStandardProcedure(PortFD, command) < 0)
457  {
458  LOG_ERROR("Error setting site latitude coordinates");
459  return false;
460  }
461 
462  return true;
463 }
464 
469 {
470  bool rc = goHome();
471  if (rc)
473  return rc;
474 }
475 
480 {
481  if (!isConnected())
482  return false;
483 
484  bool slewComplete = false, isHome = false;
485  char status[DRIVER_LEN] = {0};
486  if (sendCommand(":GU#", status))
487  {
488  slewComplete = strchr(status, 'N');
489  isHome = strchr(status, 'H');
490  }
491 
492  if (HomeSP.getState() == IPS_BUSY && isHome)
493  {
494  HomeSP[0].setState(ISS_OFF);
495  HomeSP.setState(IPS_OK);
496  LOG_INFO("Arrived at home.");
497  HomeSP.apply();
499  }
500  else if (TrackState == SCOPE_SLEWING)
501  {
502  // Check if LX200 is done slewing
503  if (slewComplete)
504  {
506  LOG_INFO("Slew is complete. Tracking...");
507  }
508  }
509  else if (TrackState == SCOPE_PARKING)
510  {
511  if (slewComplete)
512  {
513  SetParked(true);
514  }
515  }
516  else
517  {
518  // Tracking changed?
519  auto wasTracking = TrackStateS[INDI_ENABLED].s == ISS_ON;
520  auto nowTracking = isTracking();
521  if (wasTracking != nowTracking)
522  TrackState = nowTracking ? SCOPE_TRACKING : SCOPE_IDLE;
523  }
524 
526  {
527  EqNP.s = IPS_ALERT;
528  IDSetNumber(&EqNP, "Error reading RA/DEC.");
529  return false;
530  }
531 
532  if (HasPierSide())
533  {
534  char response[DRIVER_LEN] = {0};
535  if (sendCommand(":Gm#", response))
536  {
537  if (response[0] == 'W')
539  else if (response[0] == 'E')
541  else
543  }
544  }
545 
547 
548  return true;
549 }
550 
554 bool LX200AM5::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
555 {
556  int nbytes_written = 0, nbytes_read = 0, rc = -1;
557 
558  tcflush(PortFD, TCIOFLUSH);
559 
560  if (cmd_len > 0)
561  {
562  char hex_cmd[DRIVER_LEN * 3] = {0};
563  hexDump(hex_cmd, cmd, cmd_len);
564  LOGF_DEBUG("CMD <%s>", hex_cmd);
565  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
566  }
567  else
568  {
569  LOGF_DEBUG("CMD <%s>", cmd);
570  rc = tty_write_string(PortFD, cmd, &nbytes_written);
571  }
572 
573  if (rc != TTY_OK)
574  {
575  char errstr[MAXRBUF] = {0};
576  tty_error_msg(rc, errstr, MAXRBUF);
577  LOGF_ERROR("Serial write error: %s.", errstr);
578  return false;
579  }
580 
581  if (res == nullptr)
582  {
583  tcdrain(PortFD);
584  return true;
585  }
586 
587  if (res_len > 0)
588  rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
589  else
590  rc = tty_nread_section(PortFD, res, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
591 
592  if (rc != TTY_OK)
593  {
594  char errstr[MAXRBUF] = {0};
595  tty_error_msg(rc, errstr, MAXRBUF);
596  LOGF_ERROR("Serial read error: %s.", errstr);
597  return false;
598  }
599 
600  if (res_len > 0)
601  {
602  char hex_res[DRIVER_LEN * 3] = {0};
603  hexDump(hex_res, res, res_len);
604  LOGF_DEBUG("RES <%s>", hex_res);
605  }
606  else
607  {
608  LOGF_DEBUG("RES <%s>", res);
609  }
610 
611  tcflush(PortFD, TCIOFLUSH);
612 
613  return true;
614 }
615 
619 void LX200AM5::hexDump(char * buf, const char * data, int size)
620 {
621  for (int i = 0; i < size; i++)
622  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
623 
624  if (size > 0)
625  buf[3 * size - 1] = '\0';
626 }
627 
631 std::vector<std::string> LX200AM5::split(const std::string &input, const std::string &regex)
632 {
633  // passing -1 as the submatch index parameter performs splitting
634  std::regex re(regex);
635  std::sregex_token_iterator
636  first{input.begin(), input.end(), re, -1},
637  last;
638  return {first, last};
639 }
void setDefaultHost(const char *addressHost)
void setLANSearchEnabled(bool enabled)
void setDefaultPort(uint32_t addressPort)
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setActiveConnection(Connection::Interface *existingConnection)
setActiveConnection Switch the active connection to the passed connection plugin
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)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
IPState getState() const
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
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)
TelescopeStatus TrackState
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
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.
ISwitchVectorProperty TrackModeSP
ISwitchVectorProperty SlewRateSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Connection::TCP * tcpConnection
INumberVectorProperty EqNP
uint32_t GetTelescopeCapability() const
GetTelescopeCapability returns the capability of the Telescope.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
INumber LocationN[3]
ISwitch * TrackModeS
void setPierSide(TelescopePierSide side)
ISwitch * SlewRateS
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
ISwitch TrackStateS[2]
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
virtual bool ReadScopeStatus() override
Read telescope status.
Definition: lx200am5.cpp:479
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
Definition: lx200am5.cpp:114
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
Definition: lx200am5.cpp:405
virtual bool initProperties() override
Called to initialize basic properties required all the time.
Definition: lx200am5.cpp:53
virtual bool Park() override
Park the telescope to its home position.
Definition: lx200am5.cpp:468
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: lx200am5.cpp:242
LX200AM5()
Definition: lx200am5.cpp:36
virtual const char * getDefaultName() override
Definition: lx200am5.cpp:140
virtual bool checkConnection() override
Definition: lx200am5.cpp:148
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: lx200am5.cpp:199
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
Definition: lx200am5.cpp:433
virtual bool setUTCOffset(double offset) override
Definition: lx200am5.cpp:384
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
Definition: lx200am5.cpp:290
virtual bool setLocalDate(uint8_t days, uint8_t months, uint16_t years) override
Definition: lx200am5.cpp:395
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void setLX200Capability(uint32_t cap)
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.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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
#define MAXINDILABEL
Definition: indiapi.h:192
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:254
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
IUGetConfigOnSwitchIndex Opens configuration file and reads single switch property to find ON switch ...
Definition: indidriver.c:711
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOG_WARN(txt)
Definition: indilogger.h:73
#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 MAXRBUF
Definition: indiserver.cpp:102
int setStandardProcedure(int fd, const char *data)
#define getLX200DEC(fd, x)
Definition: lx200driver.h:118
@ LX200_24
Definition: lx200driver.h:64
#define getLX200RA(fd, x)
Definition: lx200driver.h:117
MountType getMountType(const int fd)
bool setMountType(const int fd, Pulsar2Commands::MountType mtype)
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2