Instrument Neutral Distributed Interface INDI  2.0.2
lx200_OpenAstroTech.cpp
Go to the documentation of this file.
1 /*
2  OpenAstroTech
3  Copyright (C) 2021 Anjo Krank
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 */
20 
21 #include "lx200_OpenAstroTech.h"
22 
23 #include "indicom.h"
24 #include "lx200driver.h"
25 
26 #include <cmath>
27 #include <string.h>
28 
29 #include <libnova/transform.h>
30 #include <termios.h>
31 #include <unistd.h>
32 #include <mutex>
33 
34 #define RB_MAX_LEN 64
35 #define CMD_MAX_LEN 32
36 extern std::mutex lx200CommsLock;
37 
39 {
41 }
42 
44 {
45  bool result = LX200GPS::Handshake();
46  return result;
47 }
48 
49 #define OAT_MEADE_COMMAND "OAT_MEADE_COMMAND"
50 #define OAT_DEC_LOWER_LIMIT "OAT_DEC_LOWER_LIMIT"
51 #define OAT_DEC_UPPER_LIMIT "OAT_DEC_UPPER_LIMIT"
52 #define OAT_GET_DEBUG_LEVEL "OAT_GET_DEBUG_LEVEL"
53 #define OAT_GET_ENABLED_DEBUG_LEVEL "OAT_GET_ENABLED_DEBUG_LEVEL"
54 #define OAT_SET_DEBUG_LEVEL "OAT_GET_DEBUG_LEVEL"
55 
56 const char *OAT_TAB = "Open Astro Tech";
57 
59 {
61  IUFillText(&MeadeCommandT, OAT_MEADE_COMMAND, "Result / Command", "");
62  IUFillTextVector(&MeadeCommandTP, &MeadeCommandT, 1, getDeviceName(), "Meade", "", OPTIONS_TAB, IP_RW, 0, IPS_IDLE);
64 
66  initFocuserProperties(FOCUS_TAB);
67 
68  // Polar Align Alt
69  IUFillNumber(&PolarAlignAltN, "OAT_POLAR_ALT", "Arcmin", "%.f", -140.0, 140.0, 1.0, 0);
70  IUFillNumberVector(&PolarAlignAltNP, &PolarAlignAltN, 1, m_defaultDevice->getDeviceName(), "POLAR_ALT",
71  "Polar Align Alt",
72  MOTION_TAB, IP_RW, 60, IPS_OK);
73  // Polar Align Az
74  IUFillNumber(&PolarAlignAzN, "OAT_POLAR_AZ", "Arcmin", "%.f", -320.0, 320.0, 1.0, 0);
75  IUFillNumberVector(&PolarAlignAzNP, &PolarAlignAzN, 1, m_defaultDevice->getDeviceName(), "POLAR_AZ",
76  "Polar Align Azimuth",
77  MOTION_TAB, IP_RW, 60, IPS_OK);
78 
79  // Home
80  IUFillSwitch(&HomeS, "OAT_HOME", "Home", ISS_OFF);
81  IUFillSwitchVector(&HomeSP, &HomeS, 1, m_defaultDevice->getDeviceName(),
82  "OAT_HOME", "Home", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
83 
84  // RA Home
85  IUFillNumber(&RAHomeN, "RA_HOME", "Hours", "%d", 1.0, 7.0, 1.0, 2);
86  IUFillNumberVector(&RAHomeNP, &RAHomeN, 1, m_defaultDevice->getDeviceName(),
87  "OAT_RA_HOME", "RA Home", MOTION_TAB, IP_RW, 60, IPS_IDLE);
88 
89  // RA Home
90  IUFillNumber(&RAHomeOffsetN, "OAT_RA_HOME_OFFSET", "Steps", "%d", -10000.0, 10000.0, 100.0, 0);
91  IUFillNumberVector(&RAHomeOffsetNP, &RAHomeOffsetN, 1, m_defaultDevice->getDeviceName(),
92  "OAT_RA_HOME", "RA Home Offset", MOTION_TAB, IP_RW, 60, IPS_IDLE);
93 
94  // Polar Align Alt
95  IUFillNumber(&DecLimitsN[0], "OAT_DEC_LIMIT_LOWER", "Lower", "%.f", -20000.0, 0.0, 1000.0, 0);
96  IUFillNumber(&DecLimitsN[1], "OAT_DEC_LIMIT_UPPER", "Upper", "%.f", 0.0, 50000.0, 1000.0, 0);
97  IUFillNumberVector(&DecLimitsNP, DecLimitsN, 2, m_defaultDevice->getDeviceName(), "OAT_DEC_LIMITS",
98  "DEC Limits", MOTION_TAB, IP_RW, 60, IPS_OK);
99  return true;
100 }
101 
103 {
105 
106  if (isConnected())
107  {
108  defineProperty(&MeadeCommandTP);
109  defineProperty(&PolarAlignAltNP);
110  defineProperty(&PolarAlignAzNP);
111  //defineProperty(&HomeSP);
112  //defineProperty(&RAHomeNP);
113  //defineProperty(&RAHomeOffsetNP);
114  //defineProperty(&DecLimitsNP);
115  }
116  else
117  {
118  deleteProperty(MeadeCommandTP.name);
119  deleteProperty(PolarAlignAltNP.name);
120  deleteProperty(PolarAlignAzNP.name);
121  //deleteProperty(HomeSP.name);
122  //deleteProperty(RAHomeNP.name);
123  //deleteProperty(RAHomeOffsetNP.name);
124  //deleteProperty(DecLimitsNP.name);
125  }
126 
127  return true;
128 }
129 
131  if (!isConnected())
132  return false;
133 
134  if (isSimulation()) //if Simulation is selected
135  {
136  mountSim();
137  return true;
138  }
139 
140  if(OATUpdateProperties() != 0)
141  {
142 
143  }
144  if (OATUpdateFocuser() != 0) // Update Focuser Position
145  {
146  LOG_WARN("Communication error on Focuser Update, this update aborted, will try again...");
147  }
148  return LX200GPS::ReadScopeStatus();
149 }
150 
151 int LX200_OpenAstroTech::OATUpdateProperties()
152 {
153  // we don't need to poll if we're not moving
154  if(!(
155  PolarAlignAltNP.s == IPS_BUSY || PolarAlignAzNP.s == IPS_BUSY
156  || RAHomeNP.s == IPS_BUSY
157  )) {
158  return 0;
159  }
160 
161  tcflush(PortFD, TCIOFLUSH);
162  flushIO(PortFD);
163 
164  char value[RB_MAX_LEN] = {0};
165  int rc = executeMeadeCommand(":GX#", value);
166  if (rc == 0 && strlen(value) > 10)
167  {
168  const char *motors = strchr(value, ',') + 1;
169  if(PolarAlignAzNP.s == IPS_BUSY && motors[3] =='-') {
170  PolarAlignAzNP.s = IPS_OK;
171  IDSetNumber(&PolarAlignAzNP, nullptr);
172  }
173  if(PolarAlignAltNP.s == IPS_BUSY && motors[4] =='-') {
174  PolarAlignAltNP.s = IPS_OK;
175  IDSetNumber(&PolarAlignAltNP, nullptr);
176  }
177  if(RAHomeNP.s == IPS_BUSY && value[0] == 'H')
178  {
179  RAHomeNP.s = IPS_IDLE;
180  IDSetNumber(&RAHomeNP, nullptr);
181  }
182  }
183  //updateProperties();
184  return 0;
185 }
186 
187 bool LX200_OpenAstroTech::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
188 {
189  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
190  {
191  if (!strcmp(name, MeadeCommandTP.name))
192  {
193  if(!isSimulation()) {
194  // we're using the "Set" field for the command and the actual field for the result
195  // we need to:
196  // - get the value
197  // - check if it's a command
198  // - if so, execute it, then set the result to the control
199  // the client side needs to
200  // - push ":somecmd#"
201  // - listen to change on MeadeCommand and log it
202  char * cmd = texts[0];
203  size_t len = strlen(cmd);
204  DEBUGFDEVICE(getDeviceName(), DBG_SCOPE, "Meade Command <%s>", cmd);
205  if(len > 2 && cmd[0] == ':' && cmd[len-1] == '#') {
206  IText *tp = IUFindText(&MeadeCommandTP, names[0]);
207  MeadeCommandResult[0] = 0;
208  int err = executeMeadeCommand(texts[0], MeadeCommandResult);
209  DEBUGFDEVICE(getDeviceName(), DBG_SCOPE, "Meade Command Result %d <%s>", err, MeadeCommandResult);
210  if(err == 0) {
211  MeadeCommandTP.s = IPS_OK;
212  IUSaveText(tp, MeadeCommandResult);
213  IDSetText(&MeadeCommandTP, "%s", MeadeCommandResult);
214  return true;
215  } else {
216  MeadeCommandTP.s = IPS_ALERT;
217  IUSaveText(tp, MeadeCommandResult);
218  IDSetText(&MeadeCommandTP, "%s", MeadeCommandResult);
219  return true;
220  }
221  }
222  }
223  }
224  }
225 
226  return INDI::Telescope::ISNewText(dev, name, texts, names, n);
227 }
228 
229 bool LX200_OpenAstroTech::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
230 {
231  if (strcmp(dev, getDeviceName()) == 0)
232  {
233  char read_buffer[RB_MAX_LEN] = {0};
234  if (!strcmp(name, PolarAlignAltN.name) || !strcmp(name, PolarAlignAltNP.name))
235  {
236  /*if (IUUpdateNumber(&PolarAlignAltNP, values, names, n) < 0)
237  return false;
238  */
239  LOGF_WARN("Moving Polar Alt to %.3f", values[0]);
240  snprintf(read_buffer, sizeof(read_buffer), ":MAL%.3f#", values[0]);
241  executeMeadeCommandBlind(read_buffer);
242  PolarActive = true;
243  PolarAlignAltNP.s = IPS_BUSY;
244  IDSetNumber(&PolarAlignAltNP, nullptr);
245  return true;
246  }
247  if (!strcmp(name, PolarAlignAzN.name) || !strcmp(name, PolarAlignAzNP.name))
248  {
249  /*if (IUUpdateNumber(&PolarAlignAzNP, values, names, n) < 0)
250  return false;
251  */
252  LOGF_WARN("Moving Polar Az to %.3f", values[0]);
253  snprintf(read_buffer, sizeof(read_buffer), ":MAZ%.3f#", values[0]);
254  executeMeadeCommandBlind(read_buffer);
255  PolarActive = true;
256  PolarAlignAzNP.s = IPS_BUSY;
257  IDSetNumber(&PolarAlignAzNP, nullptr);
258  return true;
259  }
260  }
261 
262  return LX200GPS::ISNewNumber(dev, name, values, names, n);
263 }
264 
265 bool LX200_OpenAstroTech::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
266 {
267  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
268  {
269  if (!strcmp(name, HomeS.name))
270  {
271  HomeSP.s = IPS_IDLE;
272  IUResetSwitch(&HomeSP);
273  /*int targetState = */IUFindOnSwitchIndex(&HomeSP);
274  return executeMeadeCommandBlind(":hF#");
275  }
276  }
277  return LX200GPS::ISNewSwitch(dev, name, states, names, n);
278 }
279 
281 {
282  return const_cast<const char *>("LX200 OpenAstroTech");
283 }
284 
285 int LX200_OpenAstroTech::executeMeadeCommand(const char *cmd, char *data)
286 {
287  bool wait = true, getchar = false;
288  int len = strlen(cmd);
289  data[0] = 0;
290  if(len > 2) {
291  if(cmd[1] == 'F') { // Fx except for Fp
292  if(!(cmd[2] == 'p' || cmd[2] == 'B')) {
293  wait = false;
294  } else if(cmd[2] == 'B') {
295  getchar = true;
296  }
297  } else if(cmd[1] == 'M' && cmd[2] == 'A') { // MAL, MAZ
298  wait = false;
299  }
300  }
301  if(!wait) {
302  return executeMeadeCommandBlind(cmd);
303  }
304  int err = 0;
305  if(getchar) {
306  int val = getCommandChar(PortFD, cmd);
307  sprintf(data, "%c", val);
308  } else {
309  err = getCommandString(PortFD, data, cmd);
310  }
311  if(err) {
312  LOGF_WARN("Executed Meade Command error: %d %s -> '%s'", err, cmd, data);
313  } else {
314  LOGF_INFO("Executed Meade Command: %d %s -> '%s'", wait, cmd, data);
315  }
316  return err;
317 }
318 
319 // stupid meade protocol... why not just always add a # after a result??
320 // now you have to know what each command will return
321 char LX200_OpenAstroTech::getCommandChar(int fd, const char * cmd)
322 {
323  char read_buffer[RB_MAX_LEN] = {0};
324  int nbytes_write = 0, nbytes_read = 0, error_type;
325 
326  /* Add mutex */
327  std::unique_lock<std::mutex> guard(lx200CommsLock);
328 
329  //LOGF_INFO("getCommandChar 1: %s -> '%s'", cmd, read_buffer);
330  if ((error_type = tty_write_string(fd, cmd, &nbytes_write)) == TTY_OK) {
331  error_type = tty_read(fd, read_buffer, 1, 5, &nbytes_read);
332  //LOGF_INFO("getCommandChar 2: %s -> '%s'", cmd, read_buffer);
333  if (nbytes_read == 1) {
334  LOGF_INFO("getCommandChar 3: %s -> '%s'", cmd, read_buffer);
335  return read_buffer[0];
336  }
337  }
338 
339  LOGF_WARN("getCommandChar error: %d %s -> '%s'", error_type, cmd, read_buffer);
340  return -1;
341 }
342 
343 bool LX200_OpenAstroTech::executeMeadeCommandBlind(const char *cmd)
344 {
345  int error_type;
346  int nbytes_write = 0;
347 
348  DEBUGF(DBG_SCOPE, "CMD <%s>", cmd);
349 
350  flushIO(PortFD);
351  /* Add mutex */
352  std::unique_lock<std::mutex> guard(lx200CommsLock);
353  tcflush(PortFD, TCIFLUSH);
354 
355  if ((error_type = tty_write_string(PortFD, cmd, &nbytes_write)) != TTY_OK) {
356  LOGF_ERROR("CHECK CONNECTION: Error sending command %s", cmd);
357  return 1;
358  }
359  LOGF_INFO("Executed Meade Command Immediate: %s", cmd);
360  return 0;
361 }
362 
363 int LX200_OpenAstroTech::flushIO(int fd)
364 {
365  tcflush(fd, TCIOFLUSH);
366  int error_type = 0;
367  int nbytes_read;
368  std::unique_lock<std::mutex> guard(lx200CommsLock);
369  tcflush(fd, TCIOFLUSH);
370  do {
371  char discard_data[RB_MAX_LEN] = {0};
372  error_type = tty_read_section_expanded(fd, discard_data, '#', 0, 1000, &nbytes_read);
373  if (error_type >= 0) {
374  LOGF_DEBUG("flushIO: Information in buffer: Bytes: %u, string: %s", nbytes_read, discard_data);
375  }
376  //LOGF_DEBUG("flushIO: error_type = %i", error_type);
377  } while (error_type > 0);
378  return 0;
379 }
380 
381 IPState LX200_OpenAstroTech::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
382 {
383  INDI_UNUSED(speed);
384  // :FRsnnn# Set focuser target position relative (in microns)
385  // Returns: Nothing
386  LOGF_ERROR("MoveFocuser shouldn't be called: %d at %d for %d", dir, speed, duration);
387  double output;
388  char read_buffer[32];
389  output = duration;
390  if (dir != FocuserDirectionLast) {
391  FocuserDirectionLast = dir;
392  LOGF_INFO("Applying backlash %d to %d", FocuserBacklash, output);
393  output += FocuserBacklash;
394  }
395  if (dir == FOCUS_INWARD) output = 0 - output;
396  snprintf(read_buffer, sizeof(read_buffer), ":FM%f#", output);
397  executeMeadeCommandBlind(read_buffer);
398  return IPS_BUSY; // Normal case, should be set to normal by update.
399 }
400 
402 {
403  if (FocusAbsPosN[0].max >= int(targetTicks) && FocusAbsPosN[0].min <= int(targetTicks))
404  {
405  char read_buffer[32];
406  snprintf(read_buffer, sizeof(read_buffer), ":Fp#");
407  if(!executeMeadeCommand(read_buffer, read_buffer)) {
408  uint32_t currentTicks = atoi(read_buffer);
409  if(FocuserDirectionLast == FOCUS_INWARD && targetTicks > currentTicks) {
410  targetTicks += FocuserBacklash;
411  FocuserDirectionLast = FOCUS_OUTWARD;
412  } else if(FocuserDirectionLast == FOCUS_OUTWARD && targetTicks < currentTicks) {
413  targetTicks -= FocuserBacklash;
414  FocuserDirectionLast = FOCUS_INWARD;
415  }
416  uint32_t relTicks = targetTicks - currentTicks;
417 
418  char read_buffer[32];
419  snprintf(read_buffer, sizeof(read_buffer), ":FM%d#", int(relTicks));
420  executeMeadeCommandBlind(read_buffer);
421  return IPS_BUSY; // Normal case, should be set to normal by update.
422  }
423  return IPS_ALERT;
424  }
425  else
426  {
427  LOG_INFO("Unable to move focuser, out of range");
428  return IPS_ALERT;
429  }
430 }
431 
433 {
434  // :FMsnnn# Set focuser target position relative (in microns)
435  // Returns: Nothing
436  char read_buffer[32];
437  if (dir != FocuserDirectionLast) {
438  FocuserDirectionLast = dir;
439  LOGF_INFO("Applying backlash %d to %d", FocuserBacklash, ticks);
440  ticks += FocuserBacklash;
441  }
442  int output = ticks;
443  if (dir == FOCUS_INWARD) output = 0 - ticks;
444  snprintf(read_buffer, sizeof(read_buffer), ":FM%d#", output);
445  executeMeadeCommandBlind(read_buffer);
446  return IPS_BUSY; // Normal case, should be set to normal by update.
447 }
448 
450 {
451 
452  LOGF_INFO("Set backlash %d", steps);
453  FocuserBacklash = steps;
454  return true;
455 }
456 
458 {
459  // :FQ# Stop the focuser
460  // Returns: Nothing
461  char cmd[CMD_MAX_LEN] = {0};
462  strncpy(cmd, ":FQ#", sizeof(cmd));
463  executeMeadeCommandBlind(cmd);
464  return IPS_OK;
465 }
466 
467 
468 void LX200_OpenAstroTech::initFocuserProperties(const char * groupName)
469 {
470  IUFillNumber(&FocusSpeedN[0], "FOCUS_SPEED_VALUE", "Focus Speed", "%3.0f", 0.0, 4.0, 1.0, 2.0);
471  IUFillNumberVector(&FocusSpeedNP, FocusSpeedN, 1, m_defaultDevice->getDeviceName(), "FOCUS_SPEED", "Speed", groupName,
472  IP_RW, 60, IPS_OK);
473 
474  IUFillNumber(&FocusTimerN[0], "FOCUS_TIMER_VALUE", "Focus Timer (ms)", "%4.0f", 0.0, 5000.0, 50.0, 1000.0);
475  IUFillNumberVector(&FocusTimerNP, FocusTimerN, 1, m_defaultDevice->getDeviceName(), "FOCUS_TIMER", "Timer", groupName,
476  IP_RW, 60, IPS_OK);
477  lastTimerValue = 1000.0;
478 
479  // Absolute Position
480  IUFillNumber(&FocusAbsPosN[0], "FOCUS_ABSOLUTE_POSITION", "Steps", "%.f", 0.0, 100000.0, 100.0, 0);
482  "Absolute Position",
483  groupName, IP_RW, 60, IPS_OK);
484 
485  // Relative Position
486  IUFillNumber(&FocusRelPosN[0], "FOCUS_RELATIVE_POSITION", "Steps", "%.f", 0.0, 100000.0, 100.0, 0);
488  "Relative Position",
489  groupName, IP_RW, 60, IPS_OK);
490 
491  // Sync
492  IUFillNumber(&FocusSyncN[0], "FOCUS_SYNC_VALUE", "Steps", "%.f", 0.0, 100000.0, 1000.0, 0);
494  groupName, IP_RW, 60, IPS_OK);
495 
496  // Maximum Position
497  IUFillNumber(&FocusMaxPosN[0], "FOCUS_MAX_VALUE", "Steps", "%.f", 1000.0, 100000.0, 10000.0, 50000.0);
498  IUFillNumberVector(&FocusMaxPosNP, FocusMaxPosN, 1, m_defaultDevice->getDeviceName(), "FOCUS_MAX", "Max. Position",
499  groupName, IP_RW, 60, IPS_OK);
500 
501  // Abort
502  IUFillSwitch(&FocusAbortS[0], "ABORT", "Abort", ISS_OFF);
503  IUFillSwitchVector(&FocusAbortSP, FocusAbortS, 1, m_defaultDevice->getDeviceName(), "FOCUS_ABORT_MOTION", "Abort Motion",
504  groupName, IP_RW,
505  ISR_ATMOST1, 60, IPS_IDLE);
506 
507  // Revese
508  IUFillSwitch(&FocusReverseS[DefaultDevice::INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
509  IUFillSwitch(&FocusReverseS[DefaultDevice::INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_ON);
511  "Reverse Motion", groupName, IP_RW,
512  ISR_1OFMANY, 60, IPS_IDLE);
513 
514  // Backlash Compensation
515  IUFillSwitch(&FocusBacklashS[DefaultDevice::INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
516  IUFillSwitch(&FocusBacklashS[DefaultDevice::INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_ON);
518  "Backlash", groupName, IP_RW,
519  ISR_1OFMANY, 60, IPS_IDLE);
520 
521  // Backlash Compensation Value
522  IUFillNumber(&FocusBacklashN[0], "FOCUS_BACKLASH_VALUE", "Steps", "%.f", 0, 1000.0, 100, 0);
524  "Backlash",
525  groupName, IP_RW, 60, IPS_OK);
526 }
527 
528 int LX200_OpenAstroTech::OATUpdateFocuser()
529 {
530  // we don't need to poll if we're not moving
531  if(!(FocusRelPosNP.s == IPS_BUSY || FocusAbsPosNP.s == IPS_BUSY)) {
532  return 0;
533  }
534 
535  tcflush(PortFD, TCIOFLUSH);
536  flushIO(PortFD);
537 
538  // get position
539  char value[RB_MAX_LEN] = {0};
540  if (!getCommandString(PortFD, value, ":Fp#")) {
541  FocusAbsPosN[0].value = atof(value);
542  IDSetNumber(&FocusAbsPosNP, nullptr);
543  LOGF_INFO("Current focuser: %d, %f from %s", FocusAbsPosN[0].value, FocusAbsPosN[0].value, value);
544  }
545  // get is_moving
546  char valueStatus = getCommandChar(PortFD, ":FB#");
547  if (valueStatus == '0')
548  {
550  IDSetNumber(&FocusRelPosNP, nullptr);
552  IDSetNumber(&FocusAbsPosNP, nullptr);
553  }
554  else if (valueStatus == '1')
555  {
557  IDSetNumber(&FocusRelPosNP, nullptr);
559  IDSetNumber(&FocusAbsPosNP, nullptr);
560  }
561  else
562  {
563  LOGF_WARN("Communication :FB# error, check connection: %d", valueStatus);
564  //INVALID REPLY
566  IDSetNumber(&FocusRelPosNP, nullptr);
568  IDSetNumber(&FocusAbsPosNP, nullptr);
569  }
571  LOGF_DEBUG("After update properties: FocusAbsPosN min: %f max: %f", FocusAbsPosN[0].min, FocusAbsPosN[0].max);
572  return 0;
573 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
INumberVectorProperty FocusSpeedNP
INumberVectorProperty FocusSyncNP
INumberVectorProperty FocusBacklashNP
ISwitchVectorProperty FocusBacklashSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
INumberVectorProperty FocusTimerNP
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
void initProperties(const char *groupName)
Initilize focuser properties. It is recommended to call this function within initProperties() of your...
INumberVectorProperty FocusMaxPosNP
ISwitchVectorProperty FocusAbortSP
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
bool updateProperties()
Called when connected state changes, to add/remove properties.
Definition: lx200gps.cpp:117
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
Definition: lx200gps.cpp:151
bool initProperties()
Called to initialize basic properties required all the time.
Definition: lx200gps.cpp:40
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool Handshake() override
perform handshake with device to check communication
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.
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 ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual const char * getDefaultName(void) override
IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
double max(void)
double min(void)
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
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_read_section_expanded(int fd, char *buf, char stop_char, long timeout_seconds, long timeout_microseconds, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:571
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
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
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
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
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indidevapi.c:56
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_WARN(fmt,...)
Definition: indilogger.h:81
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
int fd
Definition: intelliscope.c:43
std::mutex lx200CommsLock
Definition: lx200driver.cpp:56
#define RB_MAX_LEN
#define CMD_MAX_LEN
#define OAT_MEADE_COMMAND
const char * OAT_TAB
#define MINOR_VERSION
#define MAJOR_VERSION
int getCommandString(int fd, char *data, const char *cmd)
@ value
the parser finished reading a JSON value
__u8 cmd[4]
Definition: pwc-ioctl.h:2
#define currentTicks
Definition: robofocus.cpp:42
One text descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:250