Instrument Neutral Distributed Interface INDI  2.0.2
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,
64  ISR_ATMOST1, 60, IPS_IDLE);
65 
66  // Temperature Compensation
67  IUFillSwitch(&TemperatureCompensationS[TC_ENABLED], "TC_ENABLED", "Enabled", ISS_OFF);
68  IUFillSwitch(&TemperatureCompensationS[TC_DISABLED], "TC_DISABLED", "Disabled", ISS_ON);
69  IUFillSwitchVector(&TemperatureCompensationSP, TemperatureCompensationS, 2, getDeviceName(), "TC_COMPENSATE",
70  "Compensation", COMPENSATION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
71 
72  // TC State
73  IUFillSwitch(&TemperatureStateS[TC_ENABLED], "TC_ACTIVE", "Active", ISS_OFF);
74  IUFillSwitch(&TemperatureStateS[TC_DISABLED], "TC_PAUSED", "Paused", ISS_ON);
75  IUFillSwitchVector(&TemperatureStateSP, TemperatureStateS, 2, getDeviceName(), "TC_State", "State", COMPENSATION_TAB, IP_RW,
76  ISR_1OFMANY, 60, IPS_IDLE);
77 
78  // Temperature Compensation Settings
79  IUFillNumber(&TemperatureSettingsN[TC_FACTOR], "TC_FACTOR", "Factor", "%.2f", 0, 1, 0.1, 0);
80  IUFillNumber(&TemperatureSettingsN[TC_PERIOD], "TC_PERIOD", "Period (ms)", "%.f", 10, 600000, 1000, 0);
81  IUFillNumber(&TemperatureSettingsN[TC_DELTA], "TC_DELTA", "Delta (C)", "%.2f", 0, 10, 0.1, 0);
82  IUFillNumberVector(&TemperatureSettingsNP, TemperatureSettingsN, 3, getDeviceName(), "TC_SETTINGS", "Settings",
83  COMPENSATION_TAB, IP_RW, 60, IPS_IDLE);
84 
85  // Temperature Sensors
86  IUFillNumber(&TemperatureSensorN[TEMP_0], "TEMP_0", "Motor (C)", "%.2f", -60, 60, 0, 0);
87  IUFillNumber(&TemperatureSensorN[TEMP_1], "TEMP_1", "Controller (C)", "%.f", -60, 60, 0, 0);
88  IUFillNumber(&TemperatureSensorN[TEMP_AVG], "TEMP_AVG", "Average (C)", "%.2f", -60, 60, 0, 0);
89  IUFillNumberVector(&TemperatureSensorNP, TemperatureSensorN, 3, getDeviceName(), "TC_SENSOR", "Sensor", COMPENSATION_TAB,
90  IP_RO, 60, IPS_IDLE);
91 
92  // Stepper Drive
93  IUFillNumber(&StepperDriveN[CURRENT_MOVE], "STEPPER_DRIVE_CURRENT_MOVE", "Inverse Current Move", "%.f", 0, 127, 1, 25);
94  IUFillNumber(&StepperDriveN[CURRENT_HOLD], "STEPPER_DRIVE_CURRENT_HOLD", "Inverse Current Hold", "%.f", 0, 127, 1, 100);
96  &StepperDriveNP, StepperDriveN, NARRAY(StepperDriveN),
97  getDeviceName(), "STEPPER_DRIVE", "Stepper Drive", OPTIONS_TAB, IP_RW, 60, IPS_IDLE
98  );
99 
100  addAuxControls();
103 
104  return true;
105 }
106 
111 {
113 
114  if (isConnected())
115  {
116  getStartupValues();
117 
118  defineProperty(&InfoTP);
119  defineProperty(&OperationSP);
120 
121  defineProperty(&TemperatureCompensationSP);
122  defineProperty(&TemperatureStateSP);
123  defineProperty(&TemperatureSettingsNP);
124  defineProperty(&TemperatureSensorNP);
125  defineProperty(&StepperDriveNP);
126  }
127  else
128  {
129  deleteProperty(InfoTP.name);
130  deleteProperty(OperationSP.name);
131 
132  deleteProperty(TemperatureCompensationSP.name);
133  deleteProperty(TemperatureStateSP.name);
134  deleteProperty(TemperatureSettingsNP.name);
135  deleteProperty(TemperatureSensorNP.name);
136  deleteProperty(StepperDriveNP.name);
137  }
138 
139  return true;
140 }
141 
146 {
147  std::string version;
148 
149  if (!getParameter("VERSION", version))
150  return false;
151 
152  LOGF_INFO("Detected version %s", version.c_str());
153 
154  return true;
155 }
156 
161 {
162  return "Baader SteelDriveII";
163 }
164 
168 bool SteelDriveII::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
169 {
170  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
171  {
172  // Temperature Compensation
173  if (!strcmp(TemperatureCompensationSP.name, name))
174  {
175  bool enabled = !strcmp(IUFindOnSwitchName(states, names, n), TemperatureCompensationS[TC_ENABLED].name);
176  bool rc = setParameter("TCOMP", enabled ? "1" : "0");
177 
178  if (rc)
179  {
180  IUUpdateSwitch(&TemperatureCompensationSP, states, names, n);
181  TemperatureCompensationSP.s = IPS_OK;
182  LOGF_INFO("Temperature compensation is %s.", enabled ? "enabled" : "disabled");
183  }
184  else
185  {
186  TemperatureCompensationSP.s = IPS_ALERT;
187  }
188 
189  IDSetSwitch(&TemperatureCompensationSP, nullptr);
190  return true;
191  }
192 
193  // Temperature State (Paused or Active)
194  if (!strcmp(TemperatureStateSP.name, name))
195  {
196  bool active = !strcmp(IUFindOnSwitchName(states, names, n), TemperatureStateS[TC_ACTIVE].name);
197  bool rc = setParameter("TCOMP_PAUSE", active ? "0" : "1");
198 
199  if (rc)
200  {
201  IUUpdateSwitch(&TemperatureStateSP, states, names, n);
202  TemperatureStateSP.s = IPS_OK;
203  LOGF_INFO("Temperature compensation is %s.", active ? "active" : "paused");
204  }
205  else
206  {
207  TemperatureStateSP.s = IPS_ALERT;
208  }
209 
210  IDSetSwitch(&TemperatureStateSP, nullptr);
211  return true;
212  }
213 
214  // Operations
215  if (!strcmp(OperationSP.name, name))
216  {
217  IUUpdateSwitch(&OperationSP, states, names, n);
218  if (OperationS[OPERATION_RESET].s == ISS_ON)
219  {
220  IUResetSwitch(&OperationSP);
221  if (m_ConfirmFactoryReset == false)
222  {
223  LOG_WARN("Click button again to confirm factory reset.");
224  OperationSP.s = IPS_IDLE;
225  IDSetSwitch(&OperationSP, nullptr);
226  return true;
227  }
228  else
229  {
230  m_ConfirmFactoryReset = false;
231  if (!sendCommandOK("RESET"))
232  {
233  OperationSP.s = IPS_ALERT;
234  LOG_ERROR("Failed to reset to factory settings.");
235  IDSetSwitch(&OperationSP, nullptr);
236  return true;
237  }
238  }
239  }
240 
241  if (OperationS[OPERATION_REBOOT].s == ISS_ON)
242  {
243  IUResetSwitch(&OperationSP);
244  if (!sendCommand("REBOOT"))
245  {
246  OperationSP.s = IPS_ALERT;
247  LOG_ERROR("Failed to reboot device.");
248  IDSetSwitch(&OperationSP, nullptr);
249  return true;
250  }
251 
252  LOG_INFO("Device is rebooting...");
253  OperationSP.s = IPS_OK;
254  IDSetSwitch(&OperationSP, nullptr);
255  return true;
256  }
257 
258  if (OperationS[OPERATION_ZEROING].s == ISS_ON)
259  {
260  if (!sendCommandOK("SET USE_ENDSTOP:1"))
261  {
262  LOG_WARN("Failed to enable homing sensor magnet!");
263  }
264 
265  if (!sendCommandOK("ZEROING"))
266  {
267  IUResetSwitch(&OperationSP);
268  LOG_ERROR("Failed to zero to home position.");
269  OperationSP.s = IPS_ALERT;
270  }
271  else
272  {
273  OperationSP.s = IPS_BUSY;
274  LOG_INFO("Zeroing to home position in progress...");
275  }
276 
277  IDSetSwitch(&OperationSP, nullptr);
278  return true;
279  }
280  }
281 
282  }
283 
284  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
285 }
286 
290 bool SteelDriveII::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
291 {
292  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
293  {
294  if (!strcmp(TemperatureSettingsNP.name, name))
295  {
296  double factor = TemperatureSettingsN[TC_FACTOR].value;
297  double period = TemperatureSettingsN[TC_PERIOD].value;
298  double delta = TemperatureSettingsN[TC_DELTA].value;
299  bool rc1 = true, rc2 = true, rc3 = true;
300  IUUpdateNumber(&TemperatureSettingsNP, values, names, n);
301 
302  if (factor != TemperatureSettingsN[TC_FACTOR].value)
303  rc1 = setParameter("TCOMP_FACTOR", to_string(factor));
304  if (period != TemperatureSettingsN[TC_PERIOD].value)
305  rc2 = setParameter("TCOMP_PERIOD", to_string(period));
306  if (delta != TemperatureSettingsN[TC_DELTA].value)
307  rc3 = setParameter("TCOMP_DELTA", to_string(delta));
308 
309  TemperatureSettingsNP.s = (rc1 && rc2 && rc3) ? IPS_OK : IPS_ALERT;
310  IDSetNumber(&TemperatureSettingsNP, nullptr);
311  return true;
312  }
313 
314  if (!strcmp(StepperDriveNP.name, name))
315  {
316  StepperDriveNP.s = IPS_OK;
317 
318  if (StepperDriveN[CURRENT_MOVE].value != values[CURRENT_MOVE])
319  {
320  if (setParameter("CURRENT_MOVE", to_string(values[CURRENT_MOVE], 0)))
321  StepperDriveN[CURRENT_MOVE].value = values[CURRENT_MOVE];
322  else
323  StepperDriveNP.s = IPS_ALERT;
324  }
325 
326  if (StepperDriveN[CURRENT_HOLD].value != values[CURRENT_HOLD])
327  {
328  if (setParameter("CURRENT_HOLD", to_string(values[CURRENT_HOLD], 0)))
329  StepperDriveN[CURRENT_HOLD].value = values[CURRENT_HOLD];
330  else
331  StepperDriveNP.s = IPS_ALERT;
332  }
333 
334  IDSetNumber(&StepperDriveNP, nullptr);
335  return true;
336  }
337 
338  }
339 
340  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
341 }
342 
346 bool SteelDriveII::SyncFocuser(uint32_t ticks)
347 {
348  char cmd[DRIVER_LEN] = {0};
349  snprintf(cmd, DRIVER_LEN, "SET POS:%u", ticks);
350  return sendCommandOK(cmd);
351 }
352 
357 {
358  if (targetTicks < std::stoul(m_Summary[LIMIT]))
359  {
360  char cmd[DRIVER_LEN] = {0};
361  snprintf(cmd, DRIVER_LEN, "GO %u", targetTicks);
362  if (!sendCommandOK(cmd))
363  return IPS_ALERT;
364 
365  return IPS_BUSY;
366  }
367 
368  return IPS_ALERT;
369 }
370 
375 {
376  uint32_t limit = std::stoul(m_Summary[LIMIT]);
377 
378  int direction = (dir == FOCUS_INWARD) ? -1 : 1;
379  int reversed = (FocusReverseS[INDI_ENABLED].s == ISS_ON) ? -1 : 1;
380  int relative = static_cast<int>(ticks);
381  int targetAbsPosition = FocusAbsPosN[0].value + (relative * direction * reversed);
382 
383  targetAbsPosition = std::min(limit, static_cast<uint32_t>(std::max(static_cast<int>(FocusAbsPosN[0].min),
384  targetAbsPosition)));
385 
386  return MoveAbsFocuser(targetAbsPosition);
387 }
388 
393 {
394  if (!isConnected())
395  return;
396 
397  getSummary();
398 
399  uint32_t summaryPosition = std::max(0, std::stoi(m_Summary[POSITION]));
400 
401  // Check if we're idle but the focuser is in motion
402  if (FocusAbsPosNP.s != IPS_BUSY && (m_State == GOING_UP || m_State == GOING_DOWN))
403  {
405  FocusMotionS[FOCUS_INWARD].s = (m_State == GOING_DOWN) ? ISS_ON : ISS_OFF;
406  FocusMotionS[FOCUS_OUTWARD].s = (m_State == GOING_DOWN) ? ISS_OFF : ISS_ON;
410  FocusAbsPosN[0].value = summaryPosition;
411 
412  IDSetSwitch(&FocusMotionSP, nullptr);
413  IDSetNumber(&FocusRelPosNP, nullptr);
414  IDSetNumber(&FocusAbsPosNP, nullptr);
415  }
416  else if (FocusAbsPosNP.s == IPS_BUSY && (m_State == STOPPED || m_State == ZEROED))
417  {
418  if (OperationSP.s == IPS_BUSY)
419  {
420  IUResetSwitch(&OperationSP);
421  LOG_INFO("Homing is complete");
422  OperationSP.s = IPS_OK;
423  IDSetSwitch(&OperationSP, nullptr);
424  }
425 
427  FocusAbsPosN[0].value = summaryPosition;
428  if (FocusRelPosNP.s == IPS_BUSY)
429  {
431  IDSetNumber(&FocusRelPosNP, nullptr);
432  }
433  if (FocusMotionSP.s == IPS_BUSY)
434  {
436  IDSetSwitch(&FocusMotionSP, nullptr);
437  }
438 
439  IDSetNumber(&FocusAbsPosNP, nullptr);
440  }
441  else if (std::fabs(FocusAbsPosN[0].value - summaryPosition) > 0)
442  {
443  FocusAbsPosN[0].value = summaryPosition;
444  IDSetNumber(&FocusAbsPosNP, nullptr);
445  }
446 
447  if (std::fabs(FocusMaxPosN[0].value - std::stoul(m_Summary[LIMIT])) > 0)
448  {
449  FocusMaxPosN[0].value = std::stoul(m_Summary[LIMIT]);
450  IDSetNumber(&FocusMaxPosNP, nullptr);
451  }
452 
453  double temp0 = std::stod(m_Summary[TEMP0]);
454  double temp1 = std::stod(m_Summary[TEMP1]);
455  double tempa = std::stod(m_Summary[TEMPAVG]);
456 
457  if (temp0 != TemperatureSensorN[TEMP_0].value ||
458  temp1 != TemperatureSensorN[TEMP_1].value ||
459  tempa != TemperatureSensorN[TEMP_AVG].value)
460  {
461  TemperatureSensorN[TEMP_0].value = temp0;
462  TemperatureSensorN[TEMP_1].value = temp1;
463  TemperatureSensorN[TEMP_AVG].value = tempa;
464  TemperatureSensorNP.s = IPS_OK;
465  IDSetNumber(&TemperatureSensorNP, nullptr);
466  }
467 
469 }
470 
475 {
476  return sendCommandOK("STOP");
477 }
478 
483 {
484  char cmd[DRIVER_LEN] = {0};
485  snprintf(cmd, DRIVER_LEN, "SET LIMIT:%u", ticks);
486  return sendCommandOK(cmd);
487 }
488 
493 {
494  INDI_UNUSED(enabled);
495  return true;
496 }
497 
502 {
504  return true;
505 }
506 
510 void SteelDriveII::getStartupValues()
511 {
512  std::string value;
513 
514  if (getParameter("NAME", value))
515  IUSaveText(&InfoT[INFO_NAME], value.c_str());
516 
517  if (getParameter("VERSION", value))
518  IUSaveText(&InfoT[INFO_VERSION], value.c_str());
519 
520  if (getParameter("TCOMP", value))
521  {
522  TemperatureCompensationS[TC_ENABLED].s = (value == "1") ? ISS_ON : ISS_OFF;
523  TemperatureCompensationS[TC_DISABLED].s = (value == "1") ? ISS_OFF : ISS_ON;
524  }
525 
526  if (getParameter("TCOMP_FACTOR", value))
527  {
528  TemperatureSettingsN[TC_FACTOR].value = std::stod(value);
529  }
530 
531  if (getParameter("TCOMP_PERIOD", value))
532  {
533  TemperatureSettingsN[TC_PERIOD].value = std::stod(value);
534  }
535 
536  if (getParameter("TCOMP_DELTA", value))
537  {
538  TemperatureSettingsN[TC_DELTA].value = std::stod(value);
539  }
540 
541  if (getParameter("TCOMP_PAUSE", value))
542  {
543  TemperatureStateS[TC_ACTIVE].s = (value == "0") ? ISS_ON : ISS_OFF;
544  TemperatureStateS[TC_PAUSED].s = (value == "0") ? ISS_OFF : ISS_ON;
545  }
546 
547  StepperDriveNP.s = IPS_OK;
548  if (getParameter("CURRENT_MOVE", value))
549  StepperDriveN[CURRENT_MOVE].value = std::stod(value);
550  else
551  StepperDriveNP.s = IPS_ALERT;
552 
553  if (getParameter("CURRENT_HOLD", value))
554  StepperDriveN[CURRENT_HOLD].value = std::stod(value);
555  else
556  StepperDriveNP.s = IPS_ALERT;
557 
558  getSummary();
559 
560  FocusMaxPosN[0].value = std::stoul(m_Summary[LIMIT]);
561  IDSetNumber(&FocusMaxPosNP, nullptr);
562 
563  TemperatureSensorN[TEMP_0].value = std::stod(m_Summary[TEMP0]);
564  TemperatureSensorN[TEMP_1].value = std::stod(m_Summary[TEMP1]);
565  TemperatureSensorN[TEMP_AVG].value = std::stod(m_Summary[TEMPAVG]);
566 
567 }
568 
572 bool SteelDriveII::getSummary()
573 {
574  char res[DRIVER_LEN] = {0};
575 
576  if (!sendCommand("SUMMARY", res))
577  return false;
578 
579  std::vector<std::string> params = split(res, ";");
580  if (params.size() < 10)
581  return false;
582 
583  for (int i = 0; i < 10; i++)
584  {
585  std::vector<std::string> value = split(params[i], ":");
586  m_Summary[static_cast<Summary>(i)] = value[1];
587  }
588 
589  if (m_Summary[STATE] == "GOING_UP")
590  m_State = GOING_UP;
591  else if (m_Summary[STATE] == "GOING_DOWN")
592  m_State = GOING_DOWN;
593  else if (m_Summary[STATE] == "STOPPED")
594  m_State = STOPPED;
595  else if (m_Summary[STATE] == "ZEROED")
596  m_State = ZEROED;
597 
598  return true;
599 }
600 
604 bool SteelDriveII::getParameter(const std::string &parameter, std::string &value)
605 {
606  char res[DRIVER_LEN] = {0};
607 
608  std::string cmd = "GET " + parameter;
609  if (sendCommand(cmd.c_str(), res) == false)
610  return false;
611 
612  std::vector<std::string> values = split(res, ":");
613  if (values.size() != 2)
614  return false;
615 
616  value = values[1];
617 
618  return true;
619 }
620 
624 bool SteelDriveII::setParameter(const std::string &parameter, const std::string &value)
625 {
626  std::string cmd = "SET " + parameter + ":" + value;
627  return sendCommandOK(cmd.c_str());
628 }
629 
633 bool SteelDriveII::sendCommandOK(const char * cmd)
634 {
635  char res[DRIVER_LEN] = {0};
636 
637  if (!sendCommand(cmd, res))
638  return false;
639 
640  return strstr(res, "OK");
641 }
642 
646 bool SteelDriveII::sendCommand(const char * cmd, char * res, int cmd_len, int res_len)
647 {
648  int nbytes_written = 0, nbytes_read = 0, rc = -1;
649 
650  tcflush(PortFD, TCIOFLUSH);
651 
652  if (cmd_len > 0)
653  {
654  char hex_cmd[DRIVER_LEN * 3] = {0};
655  hexDump(hex_cmd, cmd, cmd_len);
656  LOGF_DEBUG("CMD <%s>", hex_cmd);
657  rc = tty_write(PortFD, cmd, cmd_len, &nbytes_written);
658  }
659  else
660  {
661  LOGF_DEBUG("CMD <%s>", cmd);
662 
663  char formatted_command[DRIVER_LEN] = {0};
664  snprintf(formatted_command, DRIVER_LEN, "$BS %s\r\n", cmd);
665  rc = tty_write_string(PortFD, formatted_command, &nbytes_written);
666  }
667 
668  if (rc != TTY_OK)
669  {
670  char errstr[MAXRBUF] = {0};
671  tty_error_msg(rc, errstr, MAXRBUF);
672  LOGF_ERROR("Serial write error: %s.", errstr);
673  return false;
674  }
675 
676  if (res == nullptr)
677  return true;
678 
679  char rawResponse[DRIVER_LEN * 2] = {0};
680 
681  if (res_len > 0)
682  rc = tty_read(PortFD, res, res_len, DRIVER_TIMEOUT, &nbytes_read);
683  else
684  {
685  // Read echo
686  tty_nread_section(PortFD, rawResponse, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
687  // Read actual respose
688  rc = tty_nread_section(PortFD, rawResponse, DRIVER_LEN, DRIVER_STOP_CHAR, DRIVER_TIMEOUT, &nbytes_read);
689  }
690 
691  if (rc != TTY_OK)
692  {
693  char errstr[MAXRBUF] = {0};
694  tty_error_msg(rc, errstr, MAXRBUF);
695  LOGF_ERROR("Serial read error: %s.", errstr);
696  return false;
697  }
698 
699  if (res_len > 0)
700  {
701  char hex_res[DRIVER_LEN * 3] = {0};
702  hexDump(hex_res, res, res_len);
703  LOGF_DEBUG("RES <%s>", hex_res);
704  }
705  else
706  {
707  // Remove extra \r\n
708  rawResponse[nbytes_read - 2] = 0;
709  // Remove the $BS
710  strncpy(res, rawResponse + 4, DRIVER_LEN);
711  LOGF_DEBUG("RES <%s>", res);
712  }
713 
714  tcflush(PortFD, TCIOFLUSH);
715 
716  return true;
717 }
718 
722 void SteelDriveII::hexDump(char * buf, const char * data, int size)
723 {
724  for (int i = 0; i < size; i++)
725  sprintf(buf + 3 * i, "%02X ", static_cast<uint8_t>(data[i]));
726 
727  if (size > 0)
728  buf[3 * size - 1] = '\0';
729 }
730 
734 std::vector<std::string> SteelDriveII::split(const std::string &input, const std::string &regex)
735 {
736  // passing -1 as the submatch index parameter performs splitting
737  std::regex re(regex);
738  std::sregex_token_iterator
739  first{input.begin(), input.end(), re, -1},
740  last;
741  return {first, last};
742 }
743 
747 template <typename T>
748 std::string SteelDriveII::to_string(const T a_value, const int n)
749 {
750  std::ostringstream out;
751  out.precision(n);
752  out << std::fixed << a_value;
753  return out.str();
754 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
ISwitchVectorProperty FocusMotionSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumberVectorProperty FocusMaxPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Connection::Serial * serialConnection
Definition: indifocuser.h:116
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
Reverse Focuser Motion.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
virtual bool ReverseFocuser(bool enabled) override
Reverse Focuser Motion.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
const char * getDefaultName() override
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: steeldrive2.cpp:50
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SyncFocuser(uint32_t ticks) override
Sync focuser.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition: indiapi.h:500
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
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_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void 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
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
Definition: indidevapi.c:137
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
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
@ value
the parser finished reading a JSON value
__u8 cmd[4]
Definition: pwc-ioctl.h:2
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250