Instrument Neutral Distributed Interface INDI  1.9.5
planewave_efa.cpp
Go to the documentation of this file.
1 /*
2  PlaneWave EFA Protocol
3 
4  Hendrick Focuser
5 
6  Copyright (C) 2020 Jasem Mutlaq (mutlaqja@ikarustech.com)
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 */
23 
24 #include "planewave_efa.h"
25 #include "indicom.h"
27 
28 #include <cmath>
29 #include <memory>
30 #include <cstring>
31 #include <termios.h>
32 #include <unistd.h>
33 #include <regex>
34 #include <sys/ioctl.h>
35 
36 static std::unique_ptr<EFA> steelDrive(new EFA());
37 
42 {
43  setVersion(1, 2);
44 
45  // Focuser Capabilities
51 }
52 
54 {
56 
57  // Focuser Information
58  IUFillText(&InfoT[INFO_VERSION], "INFO_VERSION", "Version", "NA");
59  IUFillTextVector(&InfoTP, InfoT, 1, getDeviceName(), "INFO", "Info", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
60 
61  // Focuser temperature
62  IUFillNumber(&TemperatureN[TEMPERATURE_PRIMARY], "TEMPERATURE_PRIMARY", "Primary (c)", "%.2f", -50, 70., 0., 0.);
63  IUFillNumber(&TemperatureN[TEMPERATURE_AMBIENT], "TEMPERATURE_AMBIENT", "Ambient (c)", "%.2f", -50, 70., 0., 0.);
64  IUFillNumberVector(&TemperatureNP, TemperatureN, 2, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
66 
67  // Fan Control
68  IUFillSwitch(&FanStateS[FAN_ON], "FAN_ON", "On", ISS_OFF);
69  IUFillSwitch(&FanStateS[FAN_OFF], "FAN_OFF", "Off", ISS_ON);
70  IUFillSwitchVector(&FanStateSP, FanStateS, 2, getDeviceName(), "FOCUS_FAN", "Fans", FAN_TAB, IP_RW, ISR_1OFMANY, 0,
71  IPS_IDLE);
72 
73  // Fan Control Mode
74  IUFillSwitch(&FanControlS[FAN_MANUAL], "FAN_MANUAL", "Manual", ISS_ON);
75  IUFillSwitch(&FanControlS[FAN_AUTOMATIC_ABSOLUTE], "FAN_AUTOMATIC_ABSOLUTE", "Auto. Absolute", ISS_OFF);
76  IUFillSwitch(&FanControlS[FAN_AUTOMATIC_RELATIVE], "FAN_AUTOMATIC_RELATIVE", "Auto. Relative", ISS_OFF);
77  IUFillSwitchVector(&FanControlSP, FanControlS, 3, getDeviceName(), "FOCUS_FAN_CONTROL", "Control Mode", FAN_TAB, IP_RW,
78  ISR_1OFMANY, 0, IPS_IDLE);
79 
80  // Fan Control Parameters
81  IUFillNumber(&FanControlN[FAN_MAX_ABSOLUTE], "FAN_MAX_ABSOLUTE", "Max Primary (c)", "%.2f", 0, 50., 5., 25.);
82  IUFillNumber(&FanControlN[FAN_MAX_RELATIVE], "FAN_MAX_RELATIVE", "Max Relative (c)", "%.2f", 0., 30., 1., 2.5);
83  IUFillNumber(&FanControlN[FAN_DEADZONE], "FAN_DEADZONE", "Deadzone (c)", "%.2f", 0.1, 10, 0.5, 0.5);
84  IUFillNumberVector(&FanControlNP, FanControlN, 3, getDeviceName(), "FOCUS_FAN_PARAMS", "Control Params",
85  FAN_TAB, IP_RW, 0, IPS_IDLE);
86 
87  // Fan Off on Disconnect
88  IUFillSwitch(&FanDisconnectS[FAN_OFF_ON_DISCONNECT], "FAN_OFF_ON_DISCONNECT", "Switch Off", ISS_ON);
89  IUFillSwitchVector(&FanDisconnectSP, FanDisconnectS, 1, getDeviceName(), "FOCUS_FAN_DISCONNECT", "On Disconnect", FAN_TAB,
91 
92  // Calibration Control
93  IUFillSwitch(&CalibrationStateS[CALIBRATION_ON], "CALIBRATION_ON", "Calibrated", ISS_OFF);
94  IUFillSwitch(&CalibrationStateS[CALIBRATION_OFF], "CALIBRATION_OFF", "Not Calibrated", ISS_ON);
95  IUFillSwitchVector(&CalibrationStateSP, CalibrationStateS, 2, getDeviceName(), "FOCUS_CALIBRATION", "Calibration",
97 
98  // Setup limits
99  FocusMaxPosN[0].value = 1e7;
100  FocusMaxPosN[0].max = 1e7;
101  FocusMaxPosN[0].step = FocusMaxPosN[0].max / 50;
102 
103  FocusAbsPosN[0].max = 1e7;
104  FocusAbsPosN[0].step = FocusAbsPosN[0].max / 50;
105 
106  FocusSyncN[0].max = 1e7;
107  FocusSyncN[0].step = FocusSyncN[0].max / 50;
108 
109  FocusRelPosN[0].max = FocusAbsPosN[0].max / 2;
110  FocusRelPosN[0].step = FocusRelPosN[0].max / 50;
111 
112  addAuxControls();
115 
116  // Lower RTS so serial port not monopolized and hand controller can work
117  int bits = TIOCM_RTS;
118  (void) ioctl(PortFD, TIOCMBIC, &bits);
119 
120  return true;
121 }
122 
127 {
129 
130  if (isConnected())
131  {
132  getStartupValues();
133 
134  defineProperty(&InfoTP);
135  defineProperty(&CalibrationStateSP);
136 
137  // Fan
138  defineProperty(&FanStateSP);
139  defineProperty(&FanControlSP);
140  loadConfig(true, FanControlSP.name);
141  defineProperty(&FanDisconnectSP);
142 
143  defineProperty(&TemperatureNP);
144  }
145  else
146  {
147  deleteProperty(InfoTP.name);
148  deleteProperty(CalibrationStateSP.name);
149 
150  deleteProperty(FanStateSP.name);
151  deleteProperty(FanControlSP.name);
152  deleteProperty(FanControlNP.name);
153  deleteProperty(FanDisconnectSP.name);
154 
155  deleteProperty(TemperatureNP.name);
156  }
157 
158  return true;
159 }
160 
165 {
166  if (FanDisconnectS[FAN_OFF_ON_DISCONNECT].s == ISS_ON)
167  setFanEnabled(false);
168 
169  return INDI::Focuser::Disconnect();
170 }
171 
176 {
177  std::string version;
178 
179  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
180 
181  cmd[0] = DRIVER_SOM;
182  cmd[1] = 0x03;
183  cmd[2] = DEVICE_PC;
184  cmd[3] = DEVICE_FOC;
185  cmd[4] = GET_VERSION;
186  cmd[5] = calculateCheckSum(cmd, len);
187 
188  if (!validateLengths(cmd, len))
189  return false;
190 
191  if (!sendCommand(cmd, res, len, DRIVER_LEN))
192  return false;
193 
194  version = std::to_string(res[5]) + "." + std::to_string(res[6]);
195  IUSaveText(&InfoT[INFO_VERSION], version.c_str());
196 
197  LOGF_INFO("Detected version %s", version.c_str());
198 
199  return true;
200 }
201 
205 const char *EFA::getDefaultName()
206 {
207  return "PlaneWave EFA";
208 }
209 
213 bool EFA::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
214 {
215  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
216  {
217  // Calibration State
218  if (!strcmp(CalibrationStateSP.name, name))
219  {
220  bool enabled = strcmp(CalibrationStateS[CALIBRATION_ON].name, IUFindOnSwitchName(states, names, n)) == 0;
221  if (setCalibrationEnabled(enabled))
222  {
223  IUUpdateSwitch(&CalibrationStateSP, states, names, n);
224  CalibrationStateSP.s = IPS_OK;
225  }
226  else
227  {
228  CalibrationStateSP.s = IPS_ALERT;
229  }
230 
231  IDSetSwitch(&CalibrationStateSP, nullptr);
232  return true;
233  }
234  // Fan State
235  else if (!strcmp(FanStateSP.name, name))
236  {
237  if (FanControlS[FAN_MANUAL].s == ISS_OFF)
238  {
239  FanStateSP.s = IPS_IDLE;
240  LOG_WARN("Cannot control fan while manual control is turned off.");
241  IDSetSwitch(&FanControlSP, nullptr);
242  return true;
243  }
244 
245  bool enabled = strcmp(FanStateS[FAN_ON].name, IUFindOnSwitchName(states, names, n)) == 0;
246  if (setFanEnabled(enabled))
247  {
248  IUUpdateSwitch(&FanStateSP, states, names, n);
249  FanStateSP.s = enabled ? IPS_OK : IPS_IDLE;
250  }
251  else
252  {
253  FanStateSP.s = IPS_ALERT;
254  }
255 
256  IDSetSwitch(&FanStateSP, nullptr);
257  return true;
258  }
259  // Fan Control
260  else if (!strcmp(FanControlSP.name, name))
261  {
262  IUUpdateSwitch(&FanControlSP, states, names, n);
263  if (FanControlS[FAN_MANUAL].s == ISS_ON)
264  {
265  deleteProperty(FanControlNP.name);
266  LOG_INFO("Fan is now controlled manually.");
267  }
268  else
269  {
270  LOG_INFO("Fan is now controlled automatically per the control parameters.");
271  defineProperty(&FanControlNP);
272  }
273 
274  FanControlSP.s = IPS_OK;
275  IDSetSwitch(&FanControlSP, nullptr);
276  return true;
277  }
278  // Fan Disconnect
279  else if (!strcmp(FanDisconnectSP.name, name))
280  {
281  IUUpdateSwitch(&FanDisconnectSP, states, names, n);
282 
283  if (FanDisconnectS[FAN_OFF_ON_DISCONNECT].s == ISS_ON)
284  LOG_INFO("Fan shall be turned off upon device disconnection.");
285  else
286  LOG_INFO("Fan shall left as-is upon device disconnection.");
287 
288  FanDisconnectSP.s = IPS_OK;
289  IDSetSwitch(&FanDisconnectSP, nullptr);
290  return true;
291  }
292  }
293 
294  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
295 }
296 
300 bool EFA::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
301 {
302  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
303  {
304  // Fan Params
305  if (!strcmp(FanControlNP.name, name))
306  {
307  IUUpdateNumber(&FanControlNP, values, names, n);
308  FanControlNP.s = IPS_OK;
309  IDSetNumber(&FanControlNP, nullptr);
310  return true;
311  }
312  }
313 
314  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
315 }
316 
320 bool EFA::SyncFocuser(uint32_t ticks)
321 {
322  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
323 
324  cmd[0] = DRIVER_SOM;
325  cmd[1] = 0x06;
326  cmd[2] = DEVICE_PC;
327  cmd[3] = DEVICE_FOC;
328  cmd[4] = MTR_OFFSET_CNT;
329  cmd[5] = (ticks >> 16) & 0xFF;
330  cmd[6] = (ticks >> 8) & 0xFF;
331  cmd[7] = (ticks >> 0) & 0xFF;
332  cmd[8] = calculateCheckSum(cmd, len);
333 
334  if (!validateLengths(cmd, len))
335  return false;
336 
337  if (!sendCommand(cmd, res, len, DRIVER_LEN))
338  return false;
339 
340  return (res[5] == 1);
341 }
342 
346 IPState EFA::MoveAbsFocuser(uint32_t targetTicks)
347 {
348  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
349 
350  cmd[0] = DRIVER_SOM;
351  cmd[1] = 0x06;
352  cmd[2] = DEVICE_PC;
353  cmd[3] = DEVICE_FOC;
354  cmd[4] = MTR_GOTO_POS2;
355  cmd[5] = (targetTicks >> 16) & 0xFF;
356  cmd[6] = (targetTicks >> 8) & 0xFF;
357  cmd[7] = (targetTicks >> 0) & 0xFF;
358  cmd[8] = calculateCheckSum(cmd, len);
359 
360  if (!validateLengths(cmd, len))
361  return IPS_ALERT;
362 
363  if (!sendCommand(cmd, res, len, DRIVER_LEN))
364  return IPS_ALERT;
365 
366  return (res[5] == 1) ? IPS_BUSY : IPS_ALERT;
367 }
368 
373 {
374  int direction = (dir == FOCUS_INWARD) ? -1 : 1;
375  int reversed = (FocusReverseS[INDI_ENABLED].s == ISS_ON) ? -1 : 1;
376  int relative = static_cast<int>(ticks);
377  int targetAbsPosition = FocusAbsPosN[0].value + (relative * direction * reversed);
378 
379  targetAbsPosition = std::min(static_cast<uint32_t>(FocusAbsPosN[0].max),
380  static_cast<uint32_t>(std::max(static_cast<int>(FocusAbsPosN[0].min), targetAbsPosition)));
381 
382  return MoveAbsFocuser(targetAbsPosition);
383 }
384 
389 {
390  if (!isConnected())
391  return;
392 
393  IN_TIMER = true;
394 
395  readPosition();
396 
397  if (readTemperature())
398  {
399  // Send temperature is above threshold
400  bool aboveThreshold = false;
401  for (int i = 0; i < TemperatureNP.nnp; i++)
402  {
403  if (std::fabs(TemperatureN[i].value - m_LastTemperature[i]) > TEMPERATURE_THRESHOLD)
404  {
405  aboveThreshold = true;
406  m_LastTemperature[i] = TemperatureN[i].value;
407  }
408  }
409 
410  if (aboveThreshold)
411  IDSetNumber(&TemperatureNP, nullptr);
412 
413 
414  if (FanControlS[FAN_MANUAL].s == ISS_OFF)
415  {
416  bool turnOn = false, turnOff = false;
417  const bool isFanOn = FanStateS[FAN_ON].s == ISS_ON;
418 
419  // Check if we need to do automatic regulation of fan
420  if (FanControlS[FAN_AUTOMATIC_ABSOLUTE].s == ISS_ON)
421  {
422  // Adjust delta for deadzone
423  double min_delta = FanControlN[FAN_MAX_ABSOLUTE].value - FanControlN[FAN_DEADZONE].value;
424  double max_delta = FanControlN[FAN_MAX_ABSOLUTE].value + FanControlN[FAN_DEADZONE].value;
425 
426  turnOn = TemperatureN[TEMPERATURE_PRIMARY].value > max_delta;
427  turnOff = TemperatureN[TEMPERATURE_PRIMARY].value < min_delta;
428  }
429  else if (FanControlS[FAN_AUTOMATIC_RELATIVE].s == ISS_ON)
430  {
431  // Temperature delta
432  double tDiff = TemperatureN[TEMPERATURE_PRIMARY].value - TemperatureN[TEMPERATURE_AMBIENT].value;
433  // Adjust delta for deadzone
434  double min_delta = FanControlN[FAN_MAX_RELATIVE].value - FanControlN[FAN_DEADZONE].value;
435  double max_delta = FanControlN[FAN_MAX_RELATIVE].value + FanControlN[FAN_DEADZONE].value;
436 
437  // Check if we need to turn off/on fan
438  turnOn = tDiff > max_delta;
439  turnOff = tDiff < min_delta;
440  }
441 
442  if (isFanOn && turnOff)
443  {
444  setFanEnabled(false);
445  FanStateS[FAN_ON].s = ISS_OFF;
446  FanStateS[FAN_OFF].s = ISS_ON;
447  FanStateSP.s = IPS_IDLE;
448  IDSetSwitch(&FanStateSP, nullptr);
449  }
450  else if (!isFanOn && turnOn)
451  {
452  setFanEnabled(true);
453  FanStateS[FAN_ON].s = ISS_ON;
454  FanStateS[FAN_OFF].s = ISS_OFF;
455  FanStateSP.s = IPS_OK;
456  IDSetSwitch(&FanStateSP, nullptr);
457  }
458  }
459  }
460 
462  {
463  if (isGOTOComplete())
464  {
467  IDSetNumber(&FocusAbsPosNP, nullptr);
468  IDSetNumber(&FocusRelPosNP, nullptr);
469  LOG_INFO("Focuser reached requested position.");
470  }
471  else
472  IDSetNumber(&FocusAbsPosNP, nullptr);
473  }
474  else if (std::fabs(FocusAbsPosN[0].value - m_LastPosition) > 0)
475  {
476  m_LastPosition = FocusAbsPosN[0].value;
477  IDSetNumber(&FocusAbsPosNP, nullptr);
478  }
479 
480  IN_TIMER = false;
481 
483 }
484 
485 
490 {
491  return false;
492 }
493 
497 bool EFA::SetFocuserMaxPosition(uint32_t ticks)
498 {
499  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 9;
500 
501  cmd[0] = DRIVER_SOM;
502  cmd[1] = 0x06;
503  cmd[2] = DEVICE_PC;
504  cmd[3] = DEVICE_FOC;
505  cmd[4] = MTR_SLEWLIMITMAX;
506  cmd[5] = (ticks >> 16) & 0xFF;
507  cmd[6] = (ticks >> 8) & 0xFF;
508  cmd[7] = (ticks >> 0) & 0xFF;
509  cmd[8] = calculateCheckSum(cmd, len);
510 
511  if (!validateLengths(cmd, len))
512  return false;
513 
514  if (!sendCommand(cmd, res, len, DRIVER_LEN))
515  return false;
516 
517  return (res[5] == 1);
518 }
519 
523 bool EFA::ReverseFocuser(bool enabled)
524 {
525  INDI_UNUSED(enabled);
526  return true;
527 }
528 
532 bool EFA::saveConfigItems(FILE * fp)
533 {
535 
536  IUSaveConfigSwitch(fp, &FanControlSP);
537  if (FanControlNP.s == IPS_OK)
538  IUSaveConfigNumber(fp, &FanControlNP);
539  IUSaveConfigSwitch(fp, &FanDisconnectSP);
540  return true;
541 }
542 
546 void EFA::getStartupValues()
547 {
548  readPosition();
549  readCalibrationState();
550  readFanState();
551  readTemperature();
552 
553  if (readMaxSlewLimit())
554  {
555  FocusAbsPosN[0].max = FocusMaxPosN[0].max;
556  FocusAbsPosN[0].step = FocusAbsPosN[0].max / 50;
557 
558  FocusRelPosN[0].value = FocusAbsPosN[0].max / 50;
559  FocusRelPosN[0].max = FocusAbsPosN[0].max / 2;
560  FocusRelPosN[0].step = FocusRelPosN[0].max / 50;
561 
562  FocusMaxPosN[0].value = FocusMaxPosN[0].max;
563  FocusMaxPosN[0].step = FocusMaxPosN[0].max / 50;
564 
568  }
569 }
570 
574 inline int EFA::readByte(int fd, uint8_t *buf, int timeout, int *nbytes_read)
575 {
576  return tty_read(fd, (char *)buf, 1, timeout, nbytes_read);
577 }
578 
582 inline int EFA::readBytes(int fd, uint8_t *buf, int nbytes, int timeout, int *nbytes_read)
583 {
584  return tty_read(fd, (char *)buf, nbytes, timeout, nbytes_read);
585 }
586 
590 inline int EFA::writeBytes(int fd, const uint8_t *buf, int nbytes, int *nbytes_written)
591 {
592  return tty_write(fd, (const char *)buf, nbytes, nbytes_written);
593 }
594 
598 int EFA::readPacket(int fd, uint8_t *buf, int nbytes, int timeout, int *nbytes_read)
599 {
600  int len = 0, rc = 0, read_bytes = *nbytes_read = 0;
601 
602  if (nbytes < 6) { // smallest packet is 6 bytes
603  LOGF_ERROR("Read needs at least 6 bytes; exceeds supplied buffer size (%d)", nbytes);
604  return TTY_READ_ERROR;
605  }
606 
607  for (int i = 0; i < 10; i++) {
608  // look for SOM byte
609  rc = readByte(fd, &buf[0], timeout, &read_bytes);
610  if (rc == TTY_OK && read_bytes == 1) {
611  if (buf[0] == DRIVER_SOM) {
612  break;
613  } else {
614  LOGF_DEBUG("Looking for SOM (%02X); found %d byte (%02X)", DRIVER_SOM, read_bytes, buf[0]);
615  }
616  } else {
617  char errstr[MAXRBUF] = {0};
618  tty_error_msg(rc, errstr, MAXRBUF);
619  LOGF_DEBUG("Looking for SOM (%02X); found %s", DRIVER_SOM, errstr);
620  }
621  }
622  if (rc != TTY_OK || read_bytes != 1 || buf[0] != DRIVER_SOM) {
623  LOGF_DEBUG("%s byte not encountered", "SOM");
624  if (rc == TTY_OK)
625  return TTY_TIME_OUT;
626  return rc;
627  }
628 
629  if ((rc = readByte(fd, &buf[1], timeout, &read_bytes)) != TTY_OK) {
630  LOGF_DEBUG("%s byte not encountered", "LEN");
631  return rc;
632  }
633  len = buf[1];
634 
635  // read source
636  if ((rc = readByte(fd, &buf[2], timeout, &read_bytes)) != TTY_OK) {
637  LOGF_DEBUG("%s byte not encountered", "SRC");
638  return rc;
639  }
640  // read receiver
641  if ((rc = readByte(fd, &buf[3], timeout, &read_bytes)) != TTY_OK) {
642  LOGF_DEBUG("%s byte not encountered", "RCV");
643  return rc;
644  }
645  // read command
646  if ((rc = readByte(fd, &buf[4], timeout, &read_bytes)) != TTY_OK) {
647  LOGF_DEBUG("%s byte not encountered", "CMD");
648  return rc;
649  }
650 
651  if ((len + 3) > nbytes) {
652  LOGF_ERROR("Read (%d) will exceed supplied buffer size (%d) for command %02X", (len + 3), nbytes, buf[4]);
653  return TTY_READ_ERROR;
654  }
655 
656  // read data
657  int n;
658  for (n = 0; n < (len - 3); ++n) {
659  if ((rc = readByte(fd, &buf[5 + n], timeout, &read_bytes)) != TTY_OK) {
660  LOGF_DEBUG("%s byte not encountered", "DATA");
661  return rc;
662  }
663  }
664  // read checksum
665  if ((rc = readByte(fd, &buf[5 + n], timeout, &read_bytes)) != TTY_OK) {
666  LOGF_DEBUG("%s byte not encountered", "DATA");
667  return rc;
668  }
669 
670  uint8_t chk = calculateCheckSum(buf, (len + 3));
671 
672  if (chk != buf[len + 2])
673  {
674  LOG_ERROR("Invalid checksum!");
675  return TTY_OK; // not a tty error, nbytes_read is still zero and it is used to indicate there was this problem
676  }
677 
678  *nbytes_read = len + 3;
679 
680  return rc;
681 }
682 
686 bool EFA::sendCommand(const uint8_t * cmd, uint8_t *res, uint32_t cmd_len, uint32_t res_len)
687 {
688  int nbytes_written = 0, nbytes_read = 0, bits = 0, rc = 0, hexbuflen = (DRIVER_LEN * 3 + 4);
689  char hexbuf[DRIVER_LEN * 3 + 4];
690 
691  for (int j = 0; j < 3; usleep(100000), j++)
692  {
693  // make sure RTS is lowered
694  bits = TIOCM_RTS;
695  (void) ioctl(PortFD, TIOCMBIC, &bits);
696  bits = 0;
697 
698  // Wait until CTS is cleared.
699  for (int i = 0; i < 10; i++)
700  {
701  if ((rc = ioctl(PortFD, TIOCMGET, &bits)) == 0 && (bits & TIOCM_CTS) == 0)
702  break;
703  usleep(100000);
704  }
705 
706  if (rc < 0 || (bits & TIOCM_CTS) != 0)
707  {
708  LOGF_ERROR("CTS timed out: %s", strerror(errno));
709  return false;
710  }
711 
712  // Now raise RTS
713  bits = TIOCM_RTS;
714  ioctl(PortFD, TIOCMBIS, &bits); // was TIOCMSET
715 
716  if (!IN_TIMER && efaDump(hexbuf, hexbuflen, cmd, cmd_len) != NULL) {
717  LOGF_DEBUG("CMD: %s", hexbuf);
718  }
719  rc = writeBytes(PortFD, cmd, cmd_len, &nbytes_written);
720 
721  if (rc != TTY_OK)
722  {
723  continue;
724  }
725 
726  rc = readPacket(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
727 
728  if (rc != TTY_OK || nbytes_read == 0)
729  {
730  continue;
731  }
732 
733  if ((int)cmd_len == nbytes_read && memcmp(cmd, res, cmd_len) == 0) {
734  // received an echo
735 
736  bits = TIOCM_RTS;
737  ioctl(PortFD, TIOCMBIC, &bits);
738 
739  // Next read the actual response from EFA
740  rc = readPacket(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
741 
742  if (rc != TTY_OK || nbytes_read == 0) {
743  continue;
744  }
745  } else if (efaDump(hexbuf, hexbuflen, cmd, cmd_len) != NULL) {
746  // expected there to always be an echo, so note this occurence
747  LOGF_DEBUG("no echo for command packet: %s", hexbuf);
748  }
749 
750  if (!IN_TIMER && efaDump(hexbuf, hexbuflen, res, nbytes_read) != NULL) {
751  LOGF_DEBUG("RESP: %s", hexbuf);
752  }
753 
754  if (cmd[2] != res[3] || cmd[3] != res[2] || cmd[4] != res[4]) {
755  LOGF_DEBUG("Send/Receive mismatch - %s!", "packet not for us");
756  continue;
757  }
758  break;
759  }
760 
761  // Extra lowering of RTS to make sure hand controller is made available
762  bits = TIOCM_RTS;
763  ioctl(PortFD, TIOCMBIC, &bits);
764 
765  if (rc != TTY_OK)
766  {
767  char errstr[MAXRBUF] = {0};
768  tty_error_msg(rc, errstr, MAXRBUF);
769  LOGF_ERROR("Serial I/O error: %s.", errstr);
770  return false;
771  }
772 
773  if (cmd[2] != res[3] || cmd[3] != res[2] || cmd[4] != res[4]) {
774  LOGF_ERROR("Send/Receive mismatch and %s", "timeout");
775  return false;
776  }
777 
778  return true;
779 }
780 
784 bool EFA::readPosition()
785 {
786  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
787 
788  cmd[0] = DRIVER_SOM;
789  cmd[1] = 0x03;
790  cmd[2] = DEVICE_PC;
791  cmd[3] = DEVICE_FOC;
792  cmd[4] = MTR_GET_POS;
793  cmd[5] = calculateCheckSum(cmd, len);
794 
795  if (!validateLengths(cmd, len))
796  return false;
797 
798  if (!sendCommand(cmd, res, len, DRIVER_LEN))
799  return false;
800 
801  FocusAbsPosN[0].value = res[5] << 16 | res[6] << 8 | res[7];
802  return true;
803 }
804 
808 bool EFA::readMaxSlewLimit()
809 {
810  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
811 
812  cmd[0] = DRIVER_SOM;
813  cmd[1] = 0x03;
814  cmd[2] = DEVICE_PC;
815  cmd[3] = DEVICE_FOC;
817  cmd[5] = calculateCheckSum(cmd, len);
818 
819  if (!validateLengths(cmd, len))
820  return false;
821 
822  if (!sendCommand(cmd, res, len, DRIVER_LEN))
823  return false;
824 
825  uint32_t limit = res[5] << 16 | res[6] << 8 | res[7];
826  if (limit > 0)
827  {
828  FocusMaxPosN[0].max = limit;
829  return true;
830  }
831 
832  return false;
833 
834 }
835 
839 bool EFA::isGOTOComplete()
840 {
841  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
842 
843  cmd[0] = DRIVER_SOM;
844  cmd[1] = 0x03;
845  cmd[2] = DEVICE_PC;
846  cmd[3] = DEVICE_FOC;
847  cmd[4] = MTR_GOTO_OVER;
848  cmd[5] = calculateCheckSum(cmd, len);
849 
850  if (!validateLengths(cmd, len))
851  return false;
852 
853  if (!sendCommand(cmd, res, len, DRIVER_LEN))
854  return false;
855 
856  return (res[5] != 0);
857 }
858 
862 bool EFA::setFanEnabled(bool enabled)
863 {
864  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
865 
866  cmd[0] = DRIVER_SOM;
867  cmd[1] = 0x04;
868  cmd[2] = DEVICE_PC;
869  cmd[3] = DEVICE_FAN;
870  cmd[4] = FANS_SET;
871  cmd[5] = enabled ? 1 : 0;
872  cmd[6] = calculateCheckSum(cmd, len);
873 
874  if (!validateLengths(cmd, len))
875  return false;
876 
877  if (!sendCommand(cmd, res, len, DRIVER_LEN))
878  return false;
879 
880  return (res[5] == 1);
881 }
882 
886 bool EFA::readFanState()
887 {
888  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 6;
889 
890  cmd[0] = DRIVER_SOM;
891  cmd[1] = 0x03;
892  cmd[2] = DEVICE_PC;
893  cmd[3] = DEVICE_FAN;
894  cmd[4] = FANS_GET;
895  cmd[5] = calculateCheckSum(cmd, len);
896 
897  if (!validateLengths(cmd, len))
898  return false;
899 
900  if (!sendCommand(cmd, res, len, DRIVER_LEN))
901  return false;
902 
903  bool enabled = (res[5] == 0);
904 
905  FanStateS[FAN_ON].s = enabled ? ISS_ON : ISS_OFF;
906  FanStateS[FAN_OFF].s = enabled ? ISS_OFF : ISS_ON;
907 
908  return true;
909 }
910 
914 bool EFA::setCalibrationEnabled(bool enabled)
915 {
916  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 8;
917 
918  cmd[0] = DRIVER_SOM;
919  cmd[1] = 0x05;
920  cmd[2] = DEVICE_PC;
921  cmd[3] = DEVICE_FOC;
923  cmd[5] = 0x40;
924  cmd[6] = enabled ? 1 : 0;
925  cmd[7] = calculateCheckSum(cmd, len);
926 
927  if (!validateLengths(cmd, len))
928  return false;
929 
930  if (!sendCommand(cmd, res, len, DRIVER_LEN))
931  return false;
932 
933  return (res[5] == 1);
934 }
935 
939 bool EFA::readCalibrationState()
940 {
941  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
942 
943  cmd[0] = DRIVER_SOM;
944  cmd[1] = 0x04;
945  cmd[2] = DEVICE_PC;
946  cmd[3] = DEVICE_FOC;
948  cmd[5] = 0x40;
949  cmd[6] = calculateCheckSum(cmd, len);
950 
951  if (!validateLengths(cmd, len))
952  return false;
953 
954  if (!sendCommand(cmd, res, len, DRIVER_LEN))
955  return false;
956 
957  bool enabled = (res[5] == 1);
958 
959  CalibrationStateS[CALIBRATION_ON].s = enabled ? ISS_ON : ISS_OFF;
960  CalibrationStateS[CALIBRATION_OFF].s = enabled ? ISS_OFF : ISS_ON;
961 
962  return true;
963 }
964 
968 bool EFA::readTemperature()
969 {
970  uint8_t cmd[DRIVER_LEN] = {0}, res[DRIVER_LEN] = {0}, len = 7;
971 
972  for (uint8_t i = 0; i < 2; i++)
973  {
974  cmd[0] = DRIVER_SOM;
975  cmd[1] = 0x04;
976  cmd[2] = DEVICE_PC;
977  cmd[3] = DEVICE_TEMP;
978  cmd[4] = TEMP_GET;
979  cmd[5] = i;
980  cmd[6] = calculateCheckSum(cmd, len);
981 
982  if (!validateLengths(cmd, len))
983  return false;
984 
985  if (!sendCommand(cmd, res, len, DRIVER_LEN))
986  return false;
987 
988  TemperatureN[i].value = calculateTemperature(res[5], res[6]);
989  }
990 
991  return true;
992 }
993 
997 double EFA::calculateTemperature(uint8_t byte2, uint8_t byte3)
998 {
999  if (byte2 == 0x7F && byte3 == 0x7F)
1000  return -100;
1001 
1002  int raw_temperature = byte3 << 8 | byte2;
1003  if (raw_temperature & 0x8000)
1004  raw_temperature = raw_temperature - 0x10000;
1005 
1006  return raw_temperature / 16.0;
1007 }
1008 
1012 char * EFA::efaDump(char * buf, int buflen, const uint8_t * data, uint32_t size)
1013 {
1014  int needed = 0, idx = 0;
1015 
1016  needed = size * 3 + 4; // each byte goes to 2 chars plus 1 space (or trailing null char) plus 4 marker characters
1017 
1018  if (needed > buflen) {
1019  return NULL;
1020  }
1021 
1022  for (uint32_t i = 0; i < size; i++) {
1023  if (i == 4) {
1024  (void) sprintf(buf + idx, "<%02X> ", data[i]);
1025  idx += 5;
1026  } else if (i == 5 && i < (size - 1)) {
1027  buf[idx++] = '[';
1028  for (uint32_t j = i, k = 3; j < (size - 1) && k < data[1]; j++, k++) {
1029  (void) sprintf(buf + idx, "%02X ", data[j]);
1030  idx += 3;
1031  i = j;
1032  }
1033  buf[idx - 1] = ']';
1034  buf[idx++] = ' ';
1035  } else {
1036  (void) sprintf(buf + idx, "%02X ", data[i]);
1037  idx += 3;
1038  }
1039  }
1040 
1041  buf[idx - 1] = '\0';
1042 
1043  return buf;
1044 }
1045 
1049 std::vector<std::string> EFA::split(const std::string &input, const std::string &regex)
1050 {
1051  // passing -1 as the submatch index parameter performs splitting
1052  std::regex re(regex);
1053  std::sregex_token_iterator
1054  first{input.begin(), input.end(), re, -1},
1055  last;
1056  return {first, last};
1057 }
1058 
1062 template <typename T>
1063 std::string EFA::to_string(const T a_value, const int n)
1064 {
1065  std::ostringstream out;
1066  out.precision(n);
1067  out << std::fixed << a_value;
1068  return out.str();
1069 }
1070 
1074 bool EFA::validateLengths(const uint8_t *cmd, uint32_t len)
1075 {
1076  if (len < 6) {
1077  LOGF_ERROR("packet length (%d) is too short for command %02X", len, cmd[4]);
1078  return false;
1079  }
1080  if (cmd[1] + 3 != (int)len) {
1081  LOGF_ERROR("packet length (%d) and data length (%d) discrepancy for command %02X", len, cmd[1], cmd[4]);
1082  return false;
1083  }
1084 
1085  return true;
1086 }
1087 
1091 uint8_t EFA::calculateCheckSum(const uint8_t *cmd, uint32_t len)
1092 {
1093  int32_t sum = 0;
1094 
1095  for (uint32_t i = 1; i < len - 1; i++)
1096  sum += cmd[i];
1097 
1098  return ((-sum) & 0xFF);
1099 }
EFA::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: planewave_efa.cpp:126
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::FocuserInterface::FOCUSER_CAN_SYNC
@ FOCUSER_CAN_SYNC
Definition: indifocuserinterface.h:78
EFA::DEVICE_FOC
@ DEVICE_FOC
Definition: planewave_efa.h:69
INDI::FocuserInterface::FOCUSER_CAN_REL_MOVE
@ FOCUSER_CAN_REL_MOVE
Definition: indifocuserinterface.h:75
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
IUFindOnSwitchName
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
Definition: indicom.c:1433
TTY_TIME_OUT
@ TTY_TIME_OUT
Definition: indicom.h:98
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
INDI::DefaultDevice::addAuxControls
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
Definition: defaultdevice.cpp:665
INDI::FocuserInterface::FocusMaxPosNP
INumberVectorProperty FocusMaxPosNP
Definition: indifocuserinterface.h:290
IUUpdateMinMax
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1850
fd
int fd
Definition: indiserver.c:117
IPState
IPState
Property state.
Definition: indiapi.h:158
EFA::MTR_SLEWLIMITMAX
@ MTR_SLEWLIMITMAX
Definition: planewave_efa.h:49
EFA::DEVICE_PC
@ DEVICE_PC
Definition: planewave_efa.h:67
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
EFA::MTR_SLEWLIMITGETMAX
@ MTR_SLEWLIMITGETMAX
Definition: planewave_efa.h:50
EFA::getDefaultName
const char * getDefaultName() override
Definition: planewave_efa.cpp:205
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
EFA::SyncFocuser
virtual bool SyncFocuser(uint32_t ticks) override
Sync focuser.
Definition: planewave_efa.cpp:320
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
_INumberVectorProperty::nnp
int nnp
Definition: indiapi.h:336
IUFillNumber
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: indidriver.c:348
ISR_NOFMANY
@ ISR_NOFMANY
Definition: indiapi.h:174
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
EFA::MTR_OFFSET_CNT
@ MTR_OFFSET_CNT
Definition: planewave_efa.h:47
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
EFA::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: planewave_efa.cpp:532
IUFillTextVector
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: indidriver.c:477
INDI::DefaultDevice::setDefaultPollingPeriod
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
Definition: defaultdevice.cpp:1157
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
EFA::DEVICE_TEMP
@ DEVICE_TEMP
Definition: planewave_efa.h:71
INDI::Focuser::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: indifocuser.cpp:241
EFA::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
Move Focuser relatively.
Definition: planewave_efa.cpp:372
INDI::DefaultDevice::setVersion
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
Definition: defaultdevice.cpp:1219
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
EFA::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: planewave_efa.cpp:388
INDI::Focuser::serialConnection
Connection::Serial * serialConnection
Definition: indifocuser.h:113
EFA::MTR_GET_POS
@ MTR_GET_POS
Definition: planewave_efa.h:45
TTY_READ_ERROR
@ TTY_READ_ERROR
Definition: indicom.h:95
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
EFA::FANS_GET
@ FANS_GET
Definition: planewave_efa.h:55
Connection::Serial::B_19200
@ B_19200
Definition: connectionserial.h:82
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1455
IUFillText
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: indidriver.c:369
EFA::GET_VERSION
@ GET_VERSION
Definition: planewave_efa.h:62
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
max
double max(void)
EFA::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
Move Absolute Focuser.
Definition: planewave_efa.cpp:346
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1156
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
EFA::MTR_GET_CALIBRATION_STATE
@ MTR_GET_CALIBRATION_STATE
Definition: planewave_efa.h:56
EFA::FANS_SET
@ FANS_SET
Definition: planewave_efa.h:54
Connection::Serial::setDefaultBaudRate
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
Definition: connectionserial.cpp:381
EFA
Definition: planewave_efa.h:30
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::Focuser::PortFD
int PortFD
Definition: indifocuser.h:116
EFA::EFA
EFA()
Definition: planewave_efa.cpp:41
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
INDI::FocuserInterface::FOCUS_INWARD
@ FOCUS_INWARD
Definition: indifocuserinterface.h:68
IUFillSwitchVector
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: indidriver.c:412
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
IUFillNumberVector
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: indidriver.c:455
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
connectionserial.h
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::FocuserInterface::FocusRelPosN
INumber FocusRelPosN[1]
Definition: indifocuserinterface.h:287
INDI::FocuserInterface::FOCUSER_CAN_REVERSE
@ FOCUSER_CAN_REVERSE
Definition: indifocuserinterface.h:77
INDI::Focuser::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indifocuser.cpp:120
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
EFA::MTR_GOTO_OVER
@ MTR_GOTO_OVER
Definition: planewave_efa.h:48
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::FocuserInterface::FocusRelPosNP
INumberVectorProperty FocusRelPosNP
Definition: indifocuserinterface.h:286
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
EFA::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: planewave_efa.cpp:489
planewave_efa.h
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
EFA::SetFocuserMaxPosition
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
Set Maximum Position.
Definition: planewave_efa.cpp:497
EFA::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: planewave_efa.cpp:53
EFA::ReverseFocuser
virtual bool ReverseFocuser(bool enabled) override
Reverse Focuser Motion.
Definition: planewave_efa.cpp:523
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
EFA::DEVICE_FAN
@ DEVICE_FAN
Definition: planewave_efa.h:70
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
steelDrive
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())
name
const char * name
Definition: indiserver.c:116
EFA::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: planewave_efa.cpp:300
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::FocuserInterface::FocusReverseS
ISwitch FocusReverseS[2]
Definition: indifocuserinterface.h:303
INDI::FocuserInterface::FocusMaxPosN
INumber FocusMaxPosN[1]
Definition: indifocuserinterface.h:291
EFA::MTR_GOTO_POS2
@ MTR_GOTO_POS2
Definition: planewave_efa.h:46
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
LOG_WARN
#define LOG_WARN(txt)
Definition: indilogger.h:73
EFA::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: planewave_efa.cpp:213
ISState
ISState
Switch state.
Definition: indiapi.h:148
EFA::MTR_SET_CALIBRATION_STATE
@ MTR_SET_CALIBRATION_STATE
Definition: planewave_efa.h:57
INDI::FocuserInterface::FocusSyncN
INumber FocusSyncN[1]
Definition: indifocuserinterface.h:295
EFA::TEMP_GET
@ TEMP_GET
Definition: planewave_efa.h:53
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1465
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
INDI::DefaultDevice::Disconnect
virtual bool Disconnect()
Disconnect from device.
Definition: defaultdevice.cpp:1083
TTY_OK
@ TTY_OK
Definition: indicom.h:94
EFA::Disconnect
virtual bool Disconnect() override
Disconnect from device.
Definition: planewave_efa.cpp:164
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
INDI::Focuser::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indifocuser.cpp:168
INDI::FocuserInterface::FocusAbsPosN
INumber FocusAbsPosN[1]
Definition: indifocuserinterface.h:283
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
errno
int errno
IUFillSwitch
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: indidriver.c:320
INDI::Focuser::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indifocuser.cpp:145
EFA::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: planewave_efa.cpp:175
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151