Instrument Neutral Distributed Interface INDI  1.9.5
steeldrive2.cpp
Go to the documentation of this file.
1 /*
2  Baader SteelDriveII Focuser
3 
4  Copyright (C) 2019 Jasem Mutlaq (mutlaqja@ikarustech.com)
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 
22 #include "steeldrive2.h"
23 #include "indicom.h"
25 
26 #include <cmath>
27 #include <memory>
28 #include <cstring>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <regex>
32 
33 static std::unique_ptr<SteelDriveII> steelDrive(new SteelDriveII());
34 
39 {
40  setVersion(1, 0);
41 
42  // Focuser Capabilities
48 }
49 
51 {
53 
54  // Focuser Information
55  IUFillText(&InfoT[INFO_NAME], "INFO_NAME", "Name", "NA");
56  IUFillText(&InfoT[INFO_VERSION], "INFO_VERSION", "Version", "NA");
57  IUFillTextVector(&InfoTP, InfoT, 2, getDeviceName(), "INFO", "Info", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
58 
59  // Focuser Device Operation
60  IUFillSwitch(&OperationS[OPERATION_REBOOT], "OPERATION_REBOOT", "Reboot", ISS_OFF);
61  IUFillSwitch(&OperationS[OPERATION_RESET], "OPERATION_RESET", "Factory Reset", ISS_OFF);
62  IUFillSwitch(&OperationS[OPERATION_ZEROING], "OPERATION_ZEROING", "Zero Home", ISS_OFF);
63  IUFillSwitchVector(&OperationSP, OperationS, 3, getDeviceName(), "OPERATION", "Device", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
64 
65  // Temperature Compensation
66  IUFillSwitch(&TemperatureCompensationS[TC_ENABLED], "TC_ENABLED", "Enabled", ISS_OFF);
67  IUFillSwitch(&TemperatureCompensationS[TC_DISABLED], "TC_DISABLED", "Disabled", ISS_ON);
68  IUFillSwitchVector(&TemperatureCompensationSP, TemperatureCompensationS, 2, getDeviceName(), "TC_COMPENSATE", "Compensation", COMPENSATION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
69 
70  // TC State
71  IUFillSwitch(&TemperatureStateS[TC_ENABLED], "TC_ACTIVE", "Active", ISS_OFF);
72  IUFillSwitch(&TemperatureStateS[TC_DISABLED], "TC_PAUSED", "Paused", ISS_ON);
73  IUFillSwitchVector(&TemperatureStateSP, TemperatureStateS, 2, getDeviceName(), "TC_State", "State", COMPENSATION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
74 
75  // Temperature Compensation Settings
76  IUFillNumber(&TemperatureSettingsN[TC_FACTOR], "TC_FACTOR", "Factor", "%.2f", 0, 1, 0.1, 0);
77  IUFillNumber(&TemperatureSettingsN[TC_PERIOD], "TC_PERIOD", "Period (ms)", "%.f", 10, 600000, 1000, 0);
78  IUFillNumber(&TemperatureSettingsN[TC_DELTA], "TC_DELTA", "Delta (C)", "%.2f", 0, 10, 0.1, 0);
79  IUFillNumberVector(&TemperatureSettingsNP, TemperatureSettingsN, 3, getDeviceName(), "TC_SETTINGS", "Settings", COMPENSATION_TAB, IP_RW, 60, IPS_IDLE);
80 
81  // Temperature Sensors
82  IUFillNumber(&TemperatureSensorN[TEMP_0], "TEMP_0", "Motor (C)", "%.2f", -60, 60, 0, 0);
83  IUFillNumber(&TemperatureSensorN[TEMP_1], "TEMP_1", "Controller (C)", "%.f", -60, 60, 0, 0);
84  IUFillNumber(&TemperatureSensorN[TEMP_AVG], "TEMP_AVG", "Average (C)", "%.2f", -60, 60, 0, 0);
85  IUFillNumberVector(&TemperatureSensorNP, TemperatureSensorN, 3, getDeviceName(), "TC_SENSOR", "Sensor", COMPENSATION_TAB, IP_RO, 60, IPS_IDLE);
86 
87  // Stepper Drive
88  IUFillNumber(&StepperDriveN[CURRENT_MOVE], "STEPPER_DRIVE_CURRENT_MOVE", "Inverse Current Move", "%.f", 0, 127, 1, 25);
89  IUFillNumber(&StepperDriveN[CURRENT_HOLD], "STEPPER_DRIVE_CURRENT_HOLD", "Inverse Current Hold", "%.f", 0, 127, 1, 100);
91  &StepperDriveNP, StepperDriveN, NARRAY(StepperDriveN),
92  getDeviceName(), "STEPPER_DRIVE", "Stepper Drive", OPTIONS_TAB, IP_RW, 60, IPS_IDLE
93  );
94 
98 
99  return true;
100 }
101 
106 {
108 
109  if (isConnected())
110  {
111  getStartupValues();
112 
113  defineProperty(&InfoTP);
114  defineProperty(&OperationSP);
115 
116  defineProperty(&TemperatureCompensationSP);
117  defineProperty(&TemperatureStateSP);
118  defineProperty(&TemperatureSettingsNP);
119  defineProperty(&TemperatureSensorNP);
120  defineProperty(&StepperDriveNP);
121  }
122  else
123  {
124  deleteProperty(InfoTP.name);
125  deleteProperty(OperationSP.name);
126 
127  deleteProperty(TemperatureCompensationSP.name);
128  deleteProperty(TemperatureStateSP.name);
129  deleteProperty(TemperatureSettingsNP.name);
130  deleteProperty(TemperatureSensorNP.name);
131  deleteProperty(StepperDriveNP.name);
132  }
133 
134  return true;
135 }
136 
141 {
142  std::string version;
143 
144  if (!getParameter("VERSION", version))
145  return false;
146 
147  LOGF_INFO("Detected version %s", version.c_str());
148 
149  return true;
150 }
151 
156 {
157  return "Baader SteelDriveII";
158 }
159 
163 bool SteelDriveII::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
164 {
165  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
166  {
167  // Temperature Compensation
168  if (!strcmp(TemperatureCompensationSP.name, name))
169  {
170  bool enabled = !strcmp(IUFindOnSwitchName(states, names, n), TemperatureCompensationS[TC_ENABLED].name);
171  bool rc = setParameter("TCOMP", enabled ? "1" : "0");
172 
173  if (rc)
174  {
175  IUUpdateSwitch(&TemperatureCompensationSP, states, names, n);
176  TemperatureCompensationSP.s = IPS_OK;
177  LOGF_INFO("Temperature compensation is %s.", enabled ? "enabled" : "disabled");
178  }
179  else
180  {
181  TemperatureCompensationSP.s = IPS_ALERT;
182  }
183 
184  IDSetSwitch(&TemperatureCompensationSP, nullptr);
185  return true;
186  }
187 
188  // Temperature State (Paused or Active)
189  if (!strcmp(TemperatureStateSP.name, name))
190  {
191  bool active = !strcmp(IUFindOnSwitchName(states, names, n), TemperatureStateS[TC_ACTIVE].name);
192  bool rc = setParameter("TCOMP_PAUSE", active ? "0" : "1");
193 
194  if (rc)
195  {
196  IUUpdateSwitch(&TemperatureStateSP, states, names, n);
197  TemperatureStateSP.s = IPS_OK;
198  LOGF_INFO("Temperature compensation is %s.", active ? "active" : "paused");
199  }
200  else
201  {
202  TemperatureStateSP.s = IPS_ALERT;
203  }
204 
205  IDSetSwitch(&TemperatureStateSP, nullptr);
206  return true;
207  }
208 
209  // Operations
210  if (!strcmp(OperationSP.name, name))
211  {
212  IUUpdateSwitch(&OperationSP, states, names, n);
213  if (OperationS[OPERATION_RESET].s == ISS_ON)
214  {
215  IUResetSwitch(&OperationSP);
216  if (m_ConfirmFactoryReset == false)
217  {
218  LOG_WARN("Click button again to confirm factory reset.");
219  OperationSP.s = IPS_IDLE;
220  IDSetSwitch(&OperationSP, nullptr);
221  return true;
222  }
223  else
224  {
225  m_ConfirmFactoryReset = false;
226  if (!sendCommandOK("RESET"))
227  {
228  OperationSP.s = IPS_ALERT;
229  LOG_ERROR("Failed to reset to factory settings.");
230  IDSetSwitch(&OperationSP, nullptr);
231  return true;
232  }
233  }
234  }
235 
236  if (OperationS[OPERATION_REBOOT].s == ISS_ON)
237  {
238  IUResetSwitch(&OperationSP);
239  if (!sendCommand("REBOOT"))
240  {
241  OperationSP.s = IPS_ALERT;
242  LOG_ERROR("Failed to reboot device.");
243  IDSetSwitch(&OperationSP, nullptr);
244  return true;
245  }
246 
247  LOG_INFO("Device is rebooting...");
248  OperationSP.s = IPS_OK;
249  IDSetSwitch(&OperationSP, nullptr);
250  return true;
251  }
252 
253  if (OperationS[OPERATION_ZEROING].s == ISS_ON)
254  {
255  if (!sendCommandOK("SET USE_ENDSTOP:1"))
256  {
257  LOG_WARN("Failed to enable homing sensor magnet!");
258  }
259 
260  if (!sendCommandOK("ZEROING"))
261  {
262  IUResetSwitch(&OperationSP);
263  LOG_ERROR("Failed to zero to home position.");
264  OperationSP.s = IPS_ALERT;
265  }
266  else
267  {
268  OperationSP.s = IPS_BUSY;
269  LOG_INFO("Zeroing to home position in progress...");
270  }
271 
272  IDSetSwitch(&OperationSP, nullptr);
273  return true;
274  }
275  }
276 
277  }
278 
279  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
280 }
281 
285 bool SteelDriveII::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
286 {
287  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
288  {
289  if (!strcmp(TemperatureSettingsNP.name, name))
290  {
291  double factor = TemperatureSettingsN[TC_FACTOR].value;
292  double period = TemperatureSettingsN[TC_PERIOD].value;
293  double delta = TemperatureSettingsN[TC_DELTA].value;
294  bool rc1 = true, rc2 = true, rc3 = true;
295  IUUpdateNumber(&TemperatureSettingsNP, values, names, n);
296 
297  if (factor != TemperatureSettingsN[TC_FACTOR].value)
298  rc1 = setParameter("TCOMP_FACTOR", to_string(factor));
299  if (period != TemperatureSettingsN[TC_PERIOD].value)
300  rc2 = setParameter("TCOMP_PERIOD", to_string(period));
301  if (delta != TemperatureSettingsN[TC_DELTA].value)
302  rc3 = setParameter("TCOMP_DELTA", to_string(delta));
303 
304  TemperatureSettingsNP.s = (rc1 && rc2 && rc3) ? IPS_OK : IPS_ALERT;
305  IDSetNumber(&TemperatureSettingsNP, nullptr);
306  return true;
307  }
308 
309  if (!strcmp(StepperDriveNP.name, name))
310  {
311  StepperDriveNP.s = IPS_OK;
312 
313  if (StepperDriveN[CURRENT_MOVE].value != values[CURRENT_MOVE])
314  {
315  if (setParameter("CURRENT_MOVE", to_string(values[CURRENT_MOVE], 0)))
316  StepperDriveN[CURRENT_MOVE].value = values[CURRENT_MOVE];
317  else
318  StepperDriveNP.s = IPS_ALERT;
319  }
320 
321  if (StepperDriveN[CURRENT_HOLD].value != values[CURRENT_HOLD])
322  {
323  if (setParameter("CURRENT_HOLD", to_string(values[CURRENT_HOLD], 0)))
324  StepperDriveN[CURRENT_HOLD].value = values[CURRENT_HOLD];
325  else
326  StepperDriveNP.s = IPS_ALERT;
327  }
328 
329  IDSetNumber(&StepperDriveNP, nullptr);
330  return true;
331  }
332 
333  }
334 
335  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
336 }
337 
341 bool SteelDriveII::SyncFocuser(uint32_t ticks)
342 {
343  char cmd[DRIVER_LEN] = {0};
344  snprintf(cmd, DRIVER_LEN, "SET POS:%u", ticks);
345  return sendCommandOK(cmd);
346 }
347 
352 {
353  if (targetTicks < std::stoul(m_Summary[LIMIT]))
354  {
355  char cmd[DRIVER_LEN] = {0};
356  snprintf(cmd, DRIVER_LEN, "GO %u", targetTicks);
357  if (!sendCommandOK(cmd))
358  return IPS_ALERT;
359 
360  return IPS_BUSY;
361  }
362 
363  return IPS_ALERT;
364 }
365 
370 {
371  uint32_t limit = std::stoul(m_Summary[LIMIT]);
372 
373  int direction = (dir == FOCUS_INWARD) ? -1 : 1;
374  int reversed = (FocusReverseS[INDI_ENABLED].s == ISS_ON) ? -1 : 1;
375  int relative = static_cast<int>(ticks);
376  int targetAbsPosition = FocusAbsPosN[0].value + (relative * direction * reversed);
377 
378  targetAbsPosition = std::min(limit, static_cast<uint32_t>(std::max(static_cast<int>(FocusAbsPosN[0].min), targetAbsPosition)));
379 
380  return MoveAbsFocuser(targetAbsPosition);
381 }
382 
387 {
388  if (!isConnected())
389  return;
390 
391  getSummary();
392 
393  uint32_t summaryPosition = std::max(0, std::stoi(m_Summary[POSITION]));
394 
395  // Check if we're idle but the focuser is in motion
396  if (FocusAbsPosNP.s != IPS_BUSY && (m_State == GOING_UP || m_State == GOING_DOWN))
397  {
399  FocusMotionS[FOCUS_INWARD].s = (m_State == GOING_DOWN) ? ISS_ON : ISS_OFF;
400  FocusMotionS[FOCUS_OUTWARD].s = (m_State == GOING_DOWN) ? ISS_OFF : ISS_ON;
404  FocusAbsPosN[0].value = summaryPosition;
405 
406  IDSetSwitch(&FocusMotionSP, nullptr);
407  IDSetNumber(&FocusRelPosNP, nullptr);
408  IDSetNumber(&FocusAbsPosNP, nullptr);
409  }
410  else if (FocusAbsPosNP.s == IPS_BUSY && (m_State == STOPPED || m_State == ZEROED))
411  {
412  if (OperationSP.s == IPS_BUSY)
413  {
414  IUResetSwitch(&OperationSP);
415  LOG_INFO("Homing is complete");
416  OperationSP.s = IPS_OK;
417  IDSetSwitch(&OperationSP, nullptr);
418  }
419 
421  FocusAbsPosN[0].value = summaryPosition;
422  if (FocusRelPosNP.s == IPS_BUSY)
423  {
425  IDSetNumber(&FocusRelPosNP, nullptr);
426  }
427  if (FocusMotionSP.s == IPS_BUSY)
428  {
430  IDSetSwitch(&FocusMotionSP, nullptr);
431  }
432 
433  IDSetNumber(&FocusAbsPosNP, nullptr);
434  }
435  else if (std::fabs(FocusAbsPosN[0].value - summaryPosition) > 0)
436  {
437  FocusAbsPosN[0].value = summaryPosition;
438  IDSetNumber(&FocusAbsPosNP, nullptr);
439  }
440 
441  if (std::fabs(FocusMaxPosN[0].value - std::stoul(m_Summary[LIMIT])) > 0)
442  {
443  FocusMaxPosN[0].value = std::stoul(m_Summary[LIMIT]);
444  IDSetNumber(&FocusMaxPosNP, nullptr);
445  }
446 
447  double temp0 = std::stod(m_Summary[TEMP0]);
448  double temp1 = std::stod(m_Summary[TEMP1]);
449  double tempa = std::stod(m_Summary[TEMPAVG]);
450 
451  if (temp0 != TemperatureSensorN[TEMP_0].value ||
452  temp1 != TemperatureSensorN[TEMP_1].value ||
453  tempa != TemperatureSensorN[TEMP_AVG].value)
454  {
455  TemperatureSensorN[TEMP_0].value = temp0;
456  TemperatureSensorN[TEMP_1].value = temp1;
457  TemperatureSensorN[TEMP_AVG].value = tempa;
458  TemperatureSensorNP.s = IPS_OK;
459  IDSetNumber(&TemperatureSensorNP, nullptr);
460  }
461 
463 }
464 
469 {
470  return sendCommandOK("STOP");
471 }
472 
477 {
478  char cmd[DRIVER_LEN] = {0};
479  snprintf(cmd, DRIVER_LEN, "SET LIMIT:%u", ticks);
480  return sendCommandOK(cmd);
481 }
482 
487 {
488  INDI_UNUSED(enabled);
489  return true;
490 }
491 
496 {
498  return true;
499 }
500 
504 void SteelDriveII::getStartupValues()
505 {
506  std::string value;
507 
508  if (getParameter("NAME", value))
509  IUSaveText(&InfoT[INFO_NAME], value.c_str());
510 
511  if (getParameter("VERSION", value))
512  IUSaveText(&InfoT[INFO_VERSION], value.c_str());
513 
514  if (getParameter("TCOMP", value))
515  {
516  TemperatureCompensationS[TC_ENABLED].s = (value == "1") ? ISS_ON : ISS_OFF;
517  TemperatureCompensationS[TC_DISABLED].s = (value == "1") ? ISS_OFF : ISS_ON;
518  }
519 
520  if (getParameter("TCOMP_FACTOR", value))
521  {
522  TemperatureSettingsN[TC_FACTOR].value = std::stod(value);
523  }
524 
525  if (getParameter("TCOMP_PERIOD", value))
526  {
527  TemperatureSettingsN[TC_PERIOD].value = std::stod(value);
528  }
529 
530  if (getParameter("TCOMP_DELTA", value))
531  {
532  TemperatureSettingsN[TC_DELTA].value = std::stod(value);
533  }
534 
535  if (getParameter("TCOMP_PAUSE", value))
536  {
537  TemperatureStateS[TC_ACTIVE].s = (value == "0") ? ISS_ON : ISS_OFF;
538  TemperatureStateS[TC_PAUSED].s = (value == "0") ? ISS_OFF : ISS_ON;
539  }
540 
541  StepperDriveNP.s = IPS_OK;
542  if (getParameter("CURRENT_MOVE", value))
543  StepperDriveN[CURRENT_MOVE].value = std::stod(value);
544  else
545  StepperDriveNP.s = IPS_ALERT;
546 
547  if (getParameter("CURRENT_HOLD", value))
548  StepperDriveN[CURRENT_HOLD].value = std::stod(value);
549  else
550  StepperDriveNP.s = IPS_ALERT;
551 
552  getSummary();
553 
554  FocusMaxPosN[0].value = std::stoul(m_Summary[LIMIT]);
555  IDSetNumber(&FocusMaxPosNP, nullptr);
556 
557  TemperatureSensorN[TEMP_0].value = std::stod(m_Summary[TEMP0]);
558  TemperatureSensorN[TEMP_1].value = std::stod(m_Summary[TEMP1]);
559  TemperatureSensorN[TEMP_AVG].value = std::stod(m_Summary[TEMPAVG]);
560 
561 }
562 
566 bool SteelDriveII::getSummary()
567 {
568  char res[DRIVER_LEN] = {0};
569 
570  if (!sendCommand("SUMMARY", res))
571  return false;
572 
573  std::vector<std::string> params = split(res, ";");
574  if (params.size() < 10)
575  return false;
576 
577  for (int i = 0; i < 10; i++)
578  {
579  std::vector<std::string> value = split(params[i], ":");
580  m_Summary[static_cast<Summary>(i)] = value[1];
581  }
582 
583  if (m_Summary[STATE] == "GOING_UP")
584  m_State = GOING_UP;
585  else if (m_Summary[STATE] == "GOING_DOWN")
586  m_State = GOING_DOWN;
587  else if (m_Summary[STATE] == "STOPPED")
588  m_State = STOPPED;
589  else if (m_Summary[STATE] == "ZEROED")
590  m_State = ZEROED;
591 
592  return true;
593 }
594 
598 bool SteelDriveII::getParameter(const std::string &parameter, std::string &value)
599 {
600  char res[DRIVER_LEN] = {0};
601 
602  std::string cmd = "GET " + parameter;
603  if (sendCommand(cmd.c_str(), res) == false)
604  return false;
605 
606  std::vector<std::string> values = split(res, ":");
607  if (values.size() != 2)
608  return false;
609 
610  value = values[1];
611 
612  return true;
613 }
614 
618 bool SteelDriveII::setParameter(const std::string &parameter, const std::string &value)
619 {
620  std::string cmd = "SET " + parameter + ":" + value;
621  return sendCommandOK(cmd.c_str());
622 }
623 
627 bool SteelDriveII::sendCommandOK(const char * cmd)
628 {
629  char res[DRIVER_LEN] = {0};
630 
631  if (!sendCommand(cmd, res))
632  return false;
633 
634  return strstr(res, "OK");
635 }
636 
640 bool SteelDriveII::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
641 {
642  int nbytes_written = 0, nbytes_read = 0, rc = -1;
643 
644  tcflush(PortFD, TCIOFLUSH);
645 
646  if (cmd_len > 0)
647  {
648  char hex_cmd[DRIVER_LEN * 3] = {0};
649  hexDump(hex_cmd, cmd, cmd_len);
650  LOGF_DEBUG("CMD <%s>", hex_cmd);
651  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
652  }
653  else
654  {
655  LOGF_DEBUG("CMD <%s>", cmd);
656 
657  char formatted_command[DRIVER_LEN] = {0};
658  snprintf(formatted_command, DRIVER_LEN, "$BS %s\r\n", cmd);
659  rc = tty_write_string(PortFD, formatted_command, &nbytes_written);
660  }
661 
662  if (rc != TTY_OK)
663  {
664  char errstr[MAXRBUF] = {0};
665  tty_error_msg(rc, errstr, MAXRBUF);
666  LOGF_ERROR("Serial write error: %s.", errstr);
667  return false;
668  }
669 
670  if (res == nullptr)
671  return true;
672 
673  char rawResponse[DRIVER_LEN * 2] = {0};
674 
675  if (res_len > 0)
676  rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
677  else
678  {
679  // Read echo
680  tty_nread_section(PortFD, rawResponse, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
681  // Read actual respose
682  rc = tty_nread_section(PortFD, rawResponse, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
683  }
684 
685  if (rc != TTY_OK)
686  {
687  char errstr[MAXRBUF] = {0};
688  tty_error_msg(rc, errstr, MAXRBUF);
689  LOGF_ERROR("Serial read error: %s.", errstr);
690  return false;
691  }
692 
693  if (res_len > 0)
694  {
695  char hex_res[DRIVER_LEN * 3] = {0};
696  hexDump(hex_res, res, res_len);
697  LOGF_DEBUG("RES <%s>", hex_res);
698  }
699  else
700  {
701  // Remove extra \r\n
702  rawResponse[nbytes_read - 2] = 0;
703  // Remove the $BS
704  strncpy(res, rawResponse + 4, DRIVER_LEN);
705  LOGF_DEBUG("RES <%s>", res);
706  }
707 
708  tcflush(PortFD, TCIOFLUSH);
709 
710  return true;
711 }
712 
716 void SteelDriveII::hexDump(char * buf, const char * data, int size)
717 {
718  for (int i = 0; i < size; i++)
719  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
720 
721  if (size > 0)
722  buf[3 * size - 1] = '\0';
723 }
724 
728 std::vector<std::string> SteelDriveII::split(const std::string &input, const std::string &regex)
729 {
730  // passing -1 as the submatch index parameter performs splitting
731  std::regex re(regex);
732  std::sregex_token_iterator
733  first{input.begin(), input.end(), re, -1},
734  last;
735  return {first, last};
736 }
737 
741 template <typename T>
742 std::string SteelDriveII::to_string(const T a_value, const int n)
743 {
744  std::ostringstream out;
745  out.precision(n);
746  out << std::fixed << a_value;
747  return out.str();
748 }
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
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
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
SteelDriveII::AbortFocuser
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: steeldrive2.cpp:468
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
SteelDriveII::GOING_UP
@ GOING_UP
Definition: steeldrive2.h:33
IPState
IPState
Property state.
Definition: indiapi.h:158
tty_nread_section
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:657
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
SteelDriveII::TEMP0
@ TEMP0
Definition: steeldrive2.h:34
SteelDriveII::POSITION
@ POSITION
Definition: steeldrive2.h:34
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
SteelDriveII::getDefaultName
const char * getDefaultName() override
Definition: steeldrive2.cpp:155
NARRAY
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition: indiapi.h:499
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
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
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
OPTIONS_TAB
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Definition: defaultdevice.cpp:39
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
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
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
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
INDI::FocuserInterface::FocusMotionS
ISwitch FocusMotionS[2]
Definition: indifocuserinterface.h:275
SteelDriveII::ZEROED
@ ZEROED
Definition: steeldrive2.h:33
SteelDriveII::TEMP1
@ TEMP1
Definition: steeldrive2.h:34
INDI::Focuser::serialConnection
Connection::Serial * serialConnection
Definition: indifocuser.h:113
INDI::FocuserInterface::FOCUSER_CAN_ABORT
@ FOCUSER_CAN_ABORT
Definition: indifocuserinterface.h:76
Connection::Serial::B_19200
@ B_19200
Definition: connectionserial.h:82
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
SteelDriveII::SetFocuserMaxPosition
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
Reverse Focuser Motion.
Definition: steeldrive2.cpp:476
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
SteelDriveII::Handshake
virtual bool Handshake() override
perform handshake with device to check communication
Definition: steeldrive2.cpp:140
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
max
double max(void)
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
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
SteelDriveII::Summary
Summary
Definition: steeldrive2.h:34
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
steeldrive2.h
SteelDriveII::GOING_DOWN
@ GOING_DOWN
Definition: steeldrive2.h:33
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
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
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
SteelDriveII
Definition: steeldrive2.h:28
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::FocusMotionSP
ISwitchVectorProperty FocusMotionSP
Definition: indifocuserinterface.h:274
SteelDriveII::STOPPED
@ STOPPED
Definition: steeldrive2.h:33
INDI::FocuserInterface::FOCUSER_CAN_REVERSE
@ FOCUSER_CAN_REVERSE
Definition: indifocuserinterface.h:77
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
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
SteelDriveII::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
Definition: steeldrive2.cpp:369
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
SteelDriveII::TEMPAVG
@ TEMPAVG
Definition: steeldrive2.h:34
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
LOGF_INFO
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
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
SteelDriveII::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: steeldrive2.cpp:105
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
SteelDriveII::LIMIT
@ LIMIT
Definition: steeldrive2.h:34
SteelDriveII::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: steeldrive2.cpp:495
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
SteelDriveII::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: steeldrive2.cpp:285
steelDrive
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())
name
const char * name
Definition: indiserver.c:116
_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
SteelDriveII::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: steeldrive2.cpp:163
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
SteelDriveII::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: steeldrive2.cpp:351
SteelDriveII::STATE
@ STATE
Definition: steeldrive2.h:34
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
ISState
ISState
Switch state.
Definition: indiapi.h:148
SteelDriveII::ReverseFocuser
virtual bool ReverseFocuser(bool enabled) override
Reverse Focuser Motion.
Definition: steeldrive2.cpp:486
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
SteelDriveII::SteelDriveII
SteelDriveII()
Definition: steeldrive2.cpp:38
tty_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:465
TTY_OK
@ TTY_OK
Definition: indicom.h:94
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
SteelDriveII::SyncFocuser
virtual bool SyncFocuser(uint32_t ticks) override
Sync focuser.
Definition: steeldrive2.cpp:341
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.
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
SteelDriveII::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: steeldrive2.cpp:50
SteelDriveII::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: steeldrive2.cpp:386
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151
INDI::FocuserInterface::FOCUS_OUTWARD
@ FOCUS_OUTWARD
Definition: indifocuserinterface.h:69