Instrument Neutral Distributed Interface INDI  2.0.2
robofocus.cpp
Go to the documentation of this file.
1 /*
2  RoboFocus
3  Copyright (C) 2006 Markus Wildi (markus.wildi@datacomm.ch)
4  2011 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 "robofocus.h"
23 
24 #include "indicom.h"
25 
26 #include <memory>
27 #include <cstring>
28 #include <termios.h>
29 
30 #define RF_MAX_CMD 9
31 #define RF_TIMEOUT 3
32 
33 #define BACKLASH_READOUT 99999
34 #define MAXTRAVEL_READOUT 99999
35 
36 #define currentSpeed SpeedN[0].value
37 #define currentPosition FocusAbsPosN[0].value
38 #define currentTemperature TemperatureN[0].value
39 #define currentBacklash FocusBacklashN[0].value
40 #define currentDuty SettingsN[0].value
41 #define currentDelay SettingsN[1].value
42 #define currentTicks SettingsN[2].value
43 #define currentRelativeMovement FocusRelPosN[0].value
44 #define currentAbsoluteMovement FocusAbsPosN[0].value
45 #define currentSetBacklash SetBacklashN[0].value
46 #define currentMinPosition MinMaxPositionN[0].value
47 #define currentMaxPosition MinMaxPositionN[1].value
48 #define currentMaxTravel FocusMaxPosN[0].value
49 
50 #define SETTINGS_TAB "Settings"
51 
52 static std::unique_ptr<RoboFocus> roboFocus(new RoboFocus());
53 
55 {
58 }
59 
61 {
63 
64  /* Focuser temperature */
65  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", 0, 65000., 0., 10000.);
66  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
68 
69  /* Settings of the Robofocus */
70  IUFillNumber(&SettingsN[0], "Duty cycle", "Duty cycle", "%6.0f", 0., 255., 0., 1.0);
71  IUFillNumber(&SettingsN[1], "Step Delay", "Step delay", "%6.0f", 0., 255., 0., 1.0);
72  IUFillNumber(&SettingsN[2], "Motor Steps", "Motor steps per tick", "%6.0f", 0., 255., 0., 1.0);
73  IUFillNumberVector(&SettingsNP, SettingsN, 3, getDeviceName(), "FOCUS_SETTINGS", "Settings", SETTINGS_TAB, IP_RW, 0,
74  IPS_IDLE);
75 
76  /* Power Switches of the Robofocus */
77  IUFillSwitch(&PowerSwitchesS[0], "1", "Switch 1", ISS_OFF);
78  IUFillSwitch(&PowerSwitchesS[1], "2", "Switch 2", ISS_OFF);
79  IUFillSwitch(&PowerSwitchesS[2], "3", "Switch 3", ISS_OFF);
80  IUFillSwitch(&PowerSwitchesS[3], "4", "Switch 4", ISS_ON);
81  IUFillSwitchVector(&PowerSwitchesSP, PowerSwitchesS, 4, getDeviceName(), "SWTICHES", "Power", SETTINGS_TAB, IP_RW,
82  ISR_1OFMANY, 0, IPS_IDLE);
83 
84  /* Robofocus should stay within these limits */
85  IUFillNumber(&MinMaxPositionN[0], "MINPOS", "Minimum Tick", "%6.0f", 1., 65000., 0., 100.);
86  IUFillNumber(&MinMaxPositionN[1], "MAXPOS", "Maximum Tick", "%6.0f", 1., 65000., 0., 55000.);
87  IUFillNumberVector(&MinMaxPositionNP, MinMaxPositionN, 2, getDeviceName(), "FOCUS_MINMAXPOSITION", "Extrema",
89 
90  IUFillNumber(&MaxTravelN[0], "MAXTRAVEL", "Maximum travel", "%6.0f", 1., 64000., 0., 10000.);
91  IUFillNumberVector(&MaxTravelNP, MaxTravelN, 1, getDeviceName(), "FOCUS_MAXTRAVEL", "Max. travel", SETTINGS_TAB,
92  IP_RW, 0, IPS_IDLE);
93 
94  // Cannot change maximum position
96  FocusMaxPosN[0].value = 64000;
97 
98  /* Set Robofocus position register to this position */
99  // IUFillNumber(&SetRegisterPositionN[0], "SETPOS", "Position", "%6.0f", 0, 64000., 0., 0.);
100  // IUFillNumberVector(&SetRegisterPositionNP, SetRegisterPositionN, 1, getDeviceName(), "FOCUS_REGISTERPOSITION",
101  // "Sync", SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
102 
103  /* Backlash */
104  // IUFillNumber(&SetBacklashN[0], "SETBACKLASH", "Backlash", "%6.0f", -255., 255., 0., 0.);
105  // IUFillNumberVector(&FocusBacklashNP, SetBacklashN, 1, getDeviceName(), "FOCUS_BACKLASH", "Set Register", SETTINGS_TAB,
106  // IP_RW, 0, IPS_IDLE);
107 
108  FocusBacklashN[0].min = -255;
109  FocusBacklashN[0].max = 255;
110  FocusBacklashN[0].step = 10;
111  FocusBacklashN[0].value = 0;
112 
113  /* Relative and absolute movement */
114  FocusRelPosN[0].min = 0.;
115  FocusRelPosN[0].max = 5000.;
116  FocusRelPosN[0].value = 100;
117  FocusRelPosN[0].step = 100;
118 
119  FocusAbsPosN[0].min = 0.;
120  FocusAbsPosN[0].max = 64000.;
121  FocusAbsPosN[0].value = 0;
122  FocusAbsPosN[0].step = 1000;
123 
124  simulatedTemperature = 600.0;
125  simulatedPosition = 20000;
126 
127  addDebugControl();
129 
130  return true;
131 }
132 
134 {
136 
137  if (isConnected())
138  {
139  defineProperty(&TemperatureNP);
140  defineProperty(&PowerSwitchesSP);
141  defineProperty(&SettingsNP);
142  defineProperty(&MinMaxPositionNP);
143  defineProperty(&MaxTravelNP);
144  // defineProperty(&SetRegisterPositionNP);
145  //defineProperty(&FocusBacklashNP);
146  // defineProperty(&FocusRelPosNP);
147  // defineProperty(&FocusAbsPosNP);
148 
149  GetFocusParams();
150 
151  LOG_DEBUG("RoboFocus parameters readout complete, focuser ready for use.");
152  }
153  else
154  {
155  deleteProperty(TemperatureNP.name);
156  deleteProperty(SettingsNP.name);
157  deleteProperty(PowerSwitchesSP.name);
158  deleteProperty(MinMaxPositionNP.name);
159  deleteProperty(MaxTravelNP.name);
160  // deleteProperty(SetRegisterPositionNP.name);
161  //deleteProperty(FocusBacklashNP.name);
162  // deleteProperty(FocusRelPosNP.name);
163  // deleteProperty(FocusAbsPosNP.name);
164  }
165 
166  return true;
167 }
168 
170 {
171  char firmeware[] = "FV0000000";
172 
173  if (isSimulation())
174  {
175  timerID = SetTimer(getCurrentPollingPeriod());
176  LOG_INFO("Simulated Robofocus is online. Getting focus parameters...");
177  FocusAbsPosN[0].value = simulatedPosition;
178  updateRFFirmware(firmeware);
179  return true;
180  }
181 
182  if ((updateRFFirmware(firmeware)) < 0)
183  {
184  /* This would be the end*/
185  LOG_ERROR("Unknown error while reading Robofocus firmware.");
186  return false;
187  }
188 
189  return true;
190 }
191 
193 {
194  return "RoboFocus";
195 }
196 
197 unsigned char RoboFocus::CheckSum(char *rf_cmd)
198 {
199  char substr[255];
200  unsigned char val = 0;
201 
202  for (int i = 0; i < 8; i++)
203  substr[i] = rf_cmd[i];
204 
205  val = CalculateSum(substr);
206 
207  if (val != (unsigned char)rf_cmd[8])
208  LOGF_WARN("Checksum: Wrong (%s,%ld), %x != %x", rf_cmd, strlen(rf_cmd), val,
209  (unsigned char)rf_cmd[8]);
210 
211  return val;
212 }
213 
214 unsigned char RoboFocus::CalculateSum(const char *rf_cmd)
215 {
216  unsigned char val = 0;
217 
218  for (int i = 0; i < 8; i++)
219  val = val + (unsigned char)rf_cmd[i];
220 
221  return val % 256;
222 }
223 
224 int RoboFocus::SendCommand(char *rf_cmd)
225 {
226  int nbytes_written = 0, err_code = 0;
227  char rf_cmd_cks[32], robofocus_error[MAXRBUF];
228 
229  unsigned char val = 0;
230 
231  val = CalculateSum(rf_cmd);
232 
233  for (int i = 0; i < 8; i++)
234  rf_cmd_cks[i] = rf_cmd[i];
235 
236  rf_cmd_cks[8] = (unsigned char)val;
237  rf_cmd_cks[9] = 0;
238 
239  if (isSimulation())
240  return 0;
241 
242  tcflush(PortFD, TCIOFLUSH);
243 
244  LOGF_DEBUG("CMD (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X)", rf_cmd_cks[0],
245  rf_cmd_cks[1], rf_cmd_cks[2], rf_cmd_cks[3], rf_cmd_cks[4], rf_cmd_cks[5], rf_cmd_cks[6], rf_cmd_cks[7],
246  rf_cmd_cks[8]);
247 
248  if ((err_code = tty_write(PortFD, rf_cmd_cks, RF_MAX_CMD, &nbytes_written) != TTY_OK))
249  {
250  tty_error_msg(err_code, robofocus_error, MAXRBUF);
251  LOGF_ERROR("TTY error detected: %s", robofocus_error);
252  return -1;
253  }
254 
255  return nbytes_written;
256 }
257 
258 int RoboFocus::ReadResponse(char *buf)
259 {
260  char robofocus_error[MAXRBUF];
261  char robofocus_char[1];
262  int bytesRead = 0;
263  int err_code;
264 
265  char motion = 0;
266  bool externalMotion = false;
267 
268  if (isSimulation())
269  return RF_MAX_CMD;
270 
271  while (true)
272  {
273  if ((err_code = tty_read(PortFD, robofocus_char, 1, RF_TIMEOUT, &bytesRead)) != TTY_OK)
274  {
275  tty_error_msg(err_code, robofocus_error, MAXRBUF);
276  LOGF_ERROR("TTY error detected: %s", robofocus_error);
277  return -1;
278  }
279 
280  switch (robofocus_char[0])
281  {
282  // Catch 'I'
283  case 0x49:
284  if (motion != 0x49)
285  {
286  motion = 0x49;
287  LOG_INFO("Moving inward...");
288 
289  if (FocusAbsPosNP.s != IPS_BUSY)
290  {
291  externalMotion = true;
293  IDSetNumber(&FocusAbsPosNP, nullptr);
294  }
295  }
296  //usleep(100000);
297  break;
298 
299  // catch 'O'
300  case 0x4F:
301  if (motion != 0x4F)
302  {
303  motion = 0x4F;
304  LOG_INFO("Moving outward...");
305 
306  if (FocusAbsPosNP.s != IPS_BUSY)
307  {
308  externalMotion = true;
310  IDSetNumber(&FocusAbsPosNP, nullptr);
311  }
312  }
313  //usleep(100000);
314  break;
315 
316  // Start of frame
317  case 0x46:
318  buf[0] = 0x46;
319  // Read rest of frame
320  if ((err_code = tty_read(PortFD, buf + 1, RF_MAX_CMD - 1, RF_TIMEOUT, &bytesRead)) != TTY_OK)
321  {
322  tty_error_msg(err_code, robofocus_error, MAXRBUF);
323  LOGF_ERROR("TTY error detected: %s", robofocus_error);
324  return -1;
325  }
326 
327  if (motion != 0)
328  {
329  LOG_INFO("Stopped.");
330 
331  // If we set it busy due to external motion, let's set it to OK
332  if (externalMotion)
333  {
335  IDSetNumber(&FocusAbsPosNP, nullptr);
336  }
337  }
338 
339  tcflush(PortFD, TCIOFLUSH);
340  return (bytesRead + 1);
341  break;
342 
343  default:
344  break;
345  }
346  }
347 
348  return -1;
349 }
350 
351 int RoboFocus::updateRFPosition(double *value)
352 {
353  float temp;
354  char rf_cmd[RF_MAX_CMD];
355  int robofocus_rc;
356 
357  LOG_DEBUG("Querying Position...");
358 
359  if (isSimulation())
360  {
361  *value = simulatedPosition;
362  return 0;
363  }
364 
365  strncpy(rf_cmd, "FG000000", 9);
366 
367  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
368  return robofocus_rc;
369 
370  if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
371  return robofocus_rc;
372 
373  if (sscanf(rf_cmd, "FD%6f", &temp) < 1)
374  return -1;
375 
376  *value = (double)temp;
377 
378  LOGF_DEBUG("Position: %g", *value);
379 
380  return 0;
381 }
382 
383 int RoboFocus::updateRFTemperature(double *value)
384 {
385  LOGF_DEBUG("Update Temperature: %g", value);
386 
387  float temp;
388  char rf_cmd[32];
389  int robofocus_rc;
390 
391  strncpy(rf_cmd, "FT000000", 9);
392 
393  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
394  return robofocus_rc;
395 
396  if (isSimulation())
397  snprintf(rf_cmd, 32, "FT%6g", simulatedTemperature);
398  else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
399  return robofocus_rc;
400 
401  if (sscanf(rf_cmd, "FT%6f", &temp) < 1)
402  return -1;
403 
404  *value = (double)temp / 2. - 273.15;
405 
406  return 0;
407 }
408 
409 int RoboFocus::updateRFBacklash(double *value)
410 {
411  LOGF_DEBUG("Update Backlash: %g", value);
412 
413  float temp;
414  char rf_cmd[32];
415  char vl_tmp[4];
416  int robofocus_rc;
417  int sign = 0;
418 
419  if (isSimulation())
420  {
421  *value = FocusBacklashN[0].value;
422  return 0;
423  }
424 
425  if (*value == BACKLASH_READOUT)
426  {
427  strncpy(rf_cmd, "FB000000", 9);
428  }
429  else
430  {
431  rf_cmd[0] = 'F';
432  rf_cmd[1] = 'B';
433 
434  if (*value > 0)
435  {
436  rf_cmd[2] = '3';
437  }
438  else
439  {
440  *value = -*value;
441  rf_cmd[2] = '2';
442  }
443  rf_cmd[3] = '0';
444  rf_cmd[4] = '0';
445 
446  if (*value > 99)
447  {
448  sprintf(vl_tmp, "%3d", (int)*value);
449  }
450  else if (*value > 9)
451  {
452  sprintf(vl_tmp, "0%2d", (int)*value);
453  }
454  else
455  {
456  sprintf(vl_tmp, "00%1d", (int)*value);
457  }
458  rf_cmd[5] = vl_tmp[0];
459  rf_cmd[6] = vl_tmp[1];
460  rf_cmd[7] = vl_tmp[2];
461  }
462 
463  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
464  return robofocus_rc;
465 
466  if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
467  return robofocus_rc;
468 
469  if (sscanf(rf_cmd, "FB%1d%5f", &sign, &temp) < 1)
470  return -1;
471 
472  *value = (double)temp;
473 
474  if ((sign == 2) && (*value > 0))
475  {
476  *value = -(*value);
477  }
478 
479  return 0;
480 }
481 
482 int RoboFocus::updateRFFirmware(char *rf_cmd)
483 {
484  int robofocus_rc;
485 
486  LOG_DEBUG("Querying RoboFocus Firmware...");
487 
488  strncpy(rf_cmd, "FV000000", 9);
489 
490  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
491  return robofocus_rc;
492 
493  if (isSimulation())
494  strncpy(rf_cmd, "SIM", 4);
495  else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
496  return robofocus_rc;
497 
498  return 0;
499 }
500 
501 int RoboFocus::updateRFMotorSettings(double *duty, double *delay, double *ticks)
502 {
503  LOGF_DEBUG("Update Motor Settings: Duty (%g), Delay (%g), Ticks(%g)", *duty, *delay, *ticks);
504 
505  char rf_cmd[32];
506  int robofocus_rc;
507 
508  if (isSimulation())
509  {
510  *duty = 100;
511  *delay = 0;
512  *ticks = 0;
513  return 0;
514  }
515 
516  if ((*duty == 0) && (*delay == 0) && (*ticks == 0))
517  {
518  strncpy(rf_cmd, "FC000000", 9);
519  }
520  else
521  {
522  rf_cmd[0] = 'F';
523  rf_cmd[1] = 'C';
524  rf_cmd[2] = (char) * duty;
525  rf_cmd[3] = (char) * delay;
526  rf_cmd[4] = (char) * ticks;
527  rf_cmd[5] = '0';
528  rf_cmd[6] = '0';
529  rf_cmd[7] = '0';
530  rf_cmd[8] = 0;
531  }
532 
533  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
534  return robofocus_rc;
535 
536  if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
537  return robofocus_rc;
538 
539  *duty = (float)rf_cmd[2];
540  *delay = (float)rf_cmd[3];
541  *ticks = (float)rf_cmd[4];
542 
543  return 0;
544 }
545 
546 int RoboFocus::updateRFPositionRelativeInward(double value)
547 {
548  char rf_cmd[32];
549  int robofocus_rc;
550  //float temp ;
551  rf_cmd[0] = 0;
552 
553  LOGF_DEBUG("Update Relative Position Inward: %g", value);
554 
555  if (isSimulation())
556  {
557  simulatedPosition += value;
558  //value = simulatedPosition;
559  return 0;
560  }
561 
562  if (value > 9999)
563  {
564  sprintf(rf_cmd, "FI0%5d", (int)value);
565  }
566  else if (value > 999)
567  {
568  sprintf(rf_cmd, "FI00%4d", (int)value);
569  }
570  else if (value > 99)
571  {
572  sprintf(rf_cmd, "FI000%3d", (int)value);
573  }
574  else if (value > 9)
575  {
576  sprintf(rf_cmd, "FI0000%2d", (int)value);
577  }
578  else
579  {
580  sprintf(rf_cmd, "FI00000%1d", (int)value);
581  }
582 
583  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
584  return robofocus_rc;
585 
586  return 0;
587 }
588 
589 int RoboFocus::updateRFPositionRelativeOutward(double value)
590 {
591  char rf_cmd[32];
592  int robofocus_rc;
593  //float temp ;
594 
595  LOGF_DEBUG("Update Relative Position Outward: %g", value);
596 
597  if (isSimulation())
598  {
599  simulatedPosition -= value;
600  //value = simulatedPosition;
601  return 0;
602  }
603 
604  rf_cmd[0] = 0;
605 
606  if (value > 9999)
607  {
608  sprintf(rf_cmd, "FO0%5d", (int)value);
609  }
610  else if (value > 999)
611  {
612  sprintf(rf_cmd, "FO00%4d", (int)value);
613  }
614  else if (value > 99)
615  {
616  sprintf(rf_cmd, "FO000%3d", (int)value);
617  }
618  else if (value > 9)
619  {
620  sprintf(rf_cmd, "FO0000%2d", (int)value);
621  }
622  else
623  {
624  sprintf(rf_cmd, "FO00000%1d", (int)value);
625  }
626 
627  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
628  return robofocus_rc;
629 
630  return 0;
631 }
632 
633 int RoboFocus::updateRFPositionAbsolute(double value)
634 {
635  char rf_cmd[32];
636  int robofocus_rc;
637 
638  LOGF_DEBUG("Moving Absolute Position: %g", value);
639 
640  if (isSimulation())
641  {
642  simulatedPosition = value;
643  return 0;
644  }
645 
646  rf_cmd[0] = 0;
647 
648  if (value > 9999)
649  {
650  sprintf(rf_cmd, "FG0%5d", (int)value);
651  }
652  else if (value > 999)
653  {
654  sprintf(rf_cmd, "FG00%4d", (int)value);
655  }
656  else if (value > 99)
657  {
658  sprintf(rf_cmd, "FG000%3d", (int)value);
659  }
660  else if (value > 9)
661  {
662  sprintf(rf_cmd, "FG0000%2d", (int)value);
663  }
664  else
665  {
666  sprintf(rf_cmd, "FG00000%1d", (int)value);
667  }
668 
669  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
670  return robofocus_rc;
671 
672  return 0;
673 }
674 
675 int RoboFocus::updateRFPowerSwitches(int s, int new_sn, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR)
676 {
677  INDI_UNUSED(s);
678  char rf_cmd[32];
679  char rf_cmd_tmp[32];
680  int robofocus_rc;
681  int i = 0;
682 
683  if (isSimulation())
684  {
685  return 0;
686  }
687 
688  LOG_DEBUG("Get switch status...");
689 
690  /* Get first the status */
691  strncpy(rf_cmd_tmp, "FP000000", 9);
692 
693  if ((robofocus_rc = SendCommand(rf_cmd_tmp)) < 0)
694  return robofocus_rc;
695 
696  if ((robofocus_rc = ReadResponse(rf_cmd_tmp)) < 0)
697  return robofocus_rc;
698 
699  for (i = 0; i < 9; i++)
700  {
701  rf_cmd[i] = rf_cmd_tmp[i];
702  }
703 
704  if (rf_cmd[new_sn + 4] == '2')
705  {
706  rf_cmd[new_sn + 4] = '1';
707  }
708  else
709  {
710  rf_cmd[new_sn + 4] = '2';
711  }
712 
713  rf_cmd[8] = 0;
714 
715  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
716  return robofocus_rc;
717 
718  if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
719  return robofocus_rc;
720 
721  *cur_s1LL = *cur_s2LR = *cur_s3RL = *cur_s4RR = ISS_OFF;
722 
723  if (rf_cmd[4] == '2')
724  {
725  *cur_s1LL = ISS_ON;
726  }
727 
728  if (rf_cmd[5] == '2')
729  {
730  *cur_s2LR = ISS_ON;
731  }
732 
733  if (rf_cmd[6] == '2')
734  {
735  *cur_s3RL = ISS_ON;
736  }
737 
738  if (rf_cmd[7] == '2')
739  {
740  *cur_s4RR = ISS_ON;
741  }
742  return 0;
743 }
744 
745 int RoboFocus::updateRFMaxPosition(double *value)
746 {
747  LOG_DEBUG("Query max position...");
748 
749  float temp;
750  char rf_cmd[32];
751  char vl_tmp[6];
752  int robofocus_rc;
753  char waste[1];
754 
755  if (isSimulation())
756  {
757  return 0;
758  }
759 
760  if (*value == MAXTRAVEL_READOUT)
761  {
762  strncpy(rf_cmd, "FL000000", 9);
763  }
764  else
765  {
766  rf_cmd[0] = 'F';
767  rf_cmd[1] = 'L';
768  rf_cmd[2] = '0';
769 
770  if (*value > 9999)
771  {
772  sprintf(vl_tmp, "%5d", (int)*value);
773  }
774  else if (*value > 999)
775  {
776  sprintf(vl_tmp, "0%4d", (int)*value);
777  }
778  else if (*value > 99)
779  {
780  sprintf(vl_tmp, "00%3d", (int)*value);
781  }
782  else if (*value > 9)
783  {
784  sprintf(vl_tmp, "000%2d", (int)*value);
785  }
786  else
787  {
788  sprintf(vl_tmp, "0000%1d", (int)*value);
789  }
790  rf_cmd[3] = vl_tmp[0];
791  rf_cmd[4] = vl_tmp[1];
792  rf_cmd[5] = vl_tmp[2];
793  rf_cmd[6] = vl_tmp[3];
794  rf_cmd[7] = vl_tmp[4];
795  rf_cmd[8] = 0;
796  }
797 
798  if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
799  return robofocus_rc;
800 
801  if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
802  return robofocus_rc;
803 
804  if (sscanf(rf_cmd, "FL%1c%5f", waste, &temp) < 1)
805  return -1;
806 
807  *value = (double)temp;
808 
809  LOGF_DEBUG("Max position: %g", *value);
810 
811  return 0;
812 }
813 
814 //int RoboFocus::updateRFSetPosition(const double *value)
815 //{
816 // LOGF_DEBUG("Set Max position: %g", *value);
817 
818 // char rf_cmd[32];
819 // char vl_tmp[6];
820 // int robofocus_rc;
821 
822 // if (isSimulation())
823 // {
824 // simulatedPosition = *value;
825 // return 0;
826 // }
827 
828 // rf_cmd[0] = 'F';
829 // rf_cmd[1] = 'S';
830 // rf_cmd[2] = '0';
831 
832 // if (*value > 9999)
833 // {
834 // sprintf(vl_tmp, "%5d", (int)*value);
835 // }
836 // else if (*value > 999)
837 // {
838 // sprintf(vl_tmp, "0%4d", (int)*value);
839 // }
840 // else if (*value > 99)
841 // {
842 // sprintf(vl_tmp, "00%3d", (int)*value);
843 // }
844 // else if (*value > 9)
845 // {
846 // sprintf(vl_tmp, "000%2d", (int)*value);
847 // }
848 // else
849 // {
850 // sprintf(vl_tmp, "0000%1d", (int)*value);
851 // }
852 // rf_cmd[3] = vl_tmp[0];
853 // rf_cmd[4] = vl_tmp[1];
854 // rf_cmd[5] = vl_tmp[2];
855 // rf_cmd[6] = vl_tmp[3];
856 // rf_cmd[7] = vl_tmp[4];
857 // rf_cmd[8] = 0;
858 
859 // if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
860 // return robofocus_rc;
861 
862 // return 0;
863 //}
864 
865 bool RoboFocus::SyncFocuser(uint32_t ticks)
866 {
867  char rf_cmd[32];
868  char vl_tmp[6];
869  int ret_read_tmp;
870 
871  if (isSimulation())
872  {
873  currentPosition = ticks;
874  return true;
875  }
876 
877  rf_cmd[0] = 'F';
878  rf_cmd[1] = 'S';
879  rf_cmd[2] = '0';
880 
881  if (ticks > 9999)
882  {
883  snprintf(vl_tmp, 6, "%5d", ticks);
884  }
885  else if (ticks > 999)
886  {
887  snprintf(vl_tmp, 6, "0%4d", ticks);
888  }
889  else if (ticks > 99)
890  {
891  snprintf(vl_tmp, 6, "00%3d", ticks);
892  }
893  else if (ticks > 9)
894  {
895  snprintf(vl_tmp, 6, "000%2d", ticks);
896  }
897  else
898  {
899  snprintf(vl_tmp, 6, "0000%1d", ticks);
900  }
901  rf_cmd[3] = vl_tmp[0];
902  rf_cmd[4] = vl_tmp[1];
903  rf_cmd[5] = vl_tmp[2];
904  rf_cmd[6] = vl_tmp[3];
905  rf_cmd[7] = vl_tmp[4];
906  rf_cmd[8] = 0;
907 
908  if ((ret_read_tmp = SendCommand(rf_cmd)) < 0)
909  return false;
910 
911  return true;
912 }
913 
914 bool RoboFocus::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
915 {
916  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
917  {
918  if (strcmp(name, PowerSwitchesSP.name) == 0)
919  {
920  int ret = -1;
921  int nset = 0;
922  int i = 0;
923  int new_s = -1;
924  int new_sn = -1;
925  int cur_s1LL = 0;
926  int cur_s2LR = 0;
927  int cur_s3RL = 0;
928  int cur_s4RR = 0;
929 
930  ISwitch *sp;
931 
932  PowerSwitchesSP.s = IPS_BUSY;
933  IDSetSwitch(&PowerSwitchesSP, nullptr);
934 
935  for (nset = i = 0; i < n; i++)
936  {
937  /* Find numbers with the passed names in the SettingsNP property */
938  sp = IUFindSwitch(&PowerSwitchesSP, names[i]);
939 
940  /* If the state found is (PowerSwitchesS[0]) then process it */
941 
942  if (sp == &PowerSwitchesS[0])
943  {
944  new_s = (states[i]);
945  new_sn = 0;
946  nset++;
947  }
948  else if (sp == &PowerSwitchesS[1])
949  {
950  new_s = (states[i]);
951  new_sn = 1;
952  nset++;
953  }
954  else if (sp == &PowerSwitchesS[2])
955  {
956  new_s = (states[i]);
957  new_sn = 2;
958  nset++;
959  }
960  else if (sp == &PowerSwitchesS[3])
961  {
962  new_s = (states[i]);
963  new_sn = 3;
964  nset++;
965  }
966  }
967  if (nset == 1)
968  {
969  cur_s1LL = cur_s2LR = cur_s3RL = cur_s4RR = 0;
970 
971  if ((ret = updateRFPowerSwitches(new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
972  {
973  PowerSwitchesSP.s = IPS_ALERT;
974  IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading Robofocus power switch settings");
975  return true;
976  }
977  }
978  else
979  {
980  /* Set property state to idle */
981  PowerSwitchesSP.s = IPS_IDLE;
982 
983  IDSetNumber(&SettingsNP, "Power switch settings absent or bogus.");
984  return true;
985  }
986  }
987  }
988 
989  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
990 }
991 
992 bool RoboFocus::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
993 {
994  int nset = 0, i = 0;
995 
996  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
997  {
998  if (strcmp(name, SettingsNP.name) == 0)
999  {
1000  /* new speed */
1001  double new_duty = 0;
1002  double new_delay = 0;
1003  double new_ticks = 0;
1004  int ret = -1;
1005 
1006  for (nset = i = 0; i < n; i++)
1007  {
1008  /* Find numbers with the passed names in the SettingsNP property */
1009  INumber *eqp = IUFindNumber(&SettingsNP, names[i]);
1010 
1011  /* If the number found is (SettingsN[0]) then process it */
1012  if (eqp == &SettingsN[0])
1013  {
1014  new_duty = (values[i]);
1015  nset += static_cast<int>(new_duty >= 0 && new_duty <= 255);
1016  }
1017  else if (eqp == &SettingsN[1])
1018  {
1019  new_delay = (values[i]);
1020  nset += static_cast<int>(new_delay >= 0 && new_delay <= 255);
1021  }
1022  else if (eqp == &SettingsN[2])
1023  {
1024  new_ticks = (values[i]);
1025  nset += static_cast<int>(new_ticks >= 0 && new_ticks <= 255);
1026  }
1027  }
1028 
1029  /* Did we process the three numbers? */
1030  if (nset == 3)
1031  {
1032  /* Set the robofocus state to BUSY */
1033  SettingsNP.s = IPS_BUSY;
1034 
1035  IDSetNumber(&SettingsNP, nullptr);
1036 
1037  if ((ret = updateRFMotorSettings(&new_duty, &new_delay, &new_ticks)) < 0)
1038  {
1039  IDSetNumber(&SettingsNP, "Changing to new settings failed");
1040  return false;
1041  }
1042 
1043  currentDuty = new_duty;
1044  currentDelay = new_delay;
1045  currentTicks = new_ticks;
1046 
1047  SettingsNP.s = IPS_OK;
1048  IDSetNumber(&SettingsNP, "Motor settings are now %3.0f %3.0f %3.0f", currentDuty, currentDelay,
1049  currentTicks);
1050  return true;
1051  }
1052  else
1053  {
1054  /* Set property state to idle */
1055  SettingsNP.s = IPS_IDLE;
1056 
1057  IDSetNumber(&SettingsNP, "Settings absent or bogus.");
1058  return false;
1059  }
1060  }
1061 
1062  // if (strcmp(name, FocusBacklashNP.name) == 0)
1063  // {
1064  // double new_back = 0;
1065  // int nset = 0;
1066  // int ret = -1;
1067 
1068  // for (nset = i = 0; i < n; i++)
1069  // {
1070  // /* Find numbers with the passed names in the FocusBacklashNP property */
1071  // INumber *eqp = IUFindNumber(&FocusBacklashNP, names[i]);
1072 
1073  // /* If the number found is SetBacklash (SetBacklashN[0]) then process it */
1074  // if (eqp == &SetBacklashN[0])
1075  // {
1076  // new_back = (values[i]);
1077 
1078  // /* limits */
1079  // nset += static_cast<int>(new_back >= -0xff && new_back <= 0xff);
1080  // }
1081 
1082  // if (nset == 1)
1083  // {
1084  // /* Set the robofocus state to BUSY */
1085  // FocusBacklashNP.s = IPS_BUSY;
1086  // IDSetNumber(&FocusBacklashNP, nullptr);
1087 
1088  // if ((ret = updateRFBacklash(&new_back)) < 0)
1089  // {
1090  // FocusBacklashNP.s = IPS_IDLE;
1091  // IDSetNumber(&FocusBacklashNP, "Setting new backlash failed.");
1092 
1093  // return false;
1094  // }
1095 
1096  // currentSetBacklash = new_back;
1097  // FocusBacklashNP.s = IPS_OK;
1098  // IDSetNumber(&FocusBacklashNP, "Backlash is now %3.0f", currentSetBacklash);
1099  // return true;
1100  // }
1101  // else
1102  // {
1103  // FocusBacklashNP.s = IPS_IDLE;
1104  // IDSetNumber(&FocusBacklashNP, "Need exactly one parameter.");
1105 
1106  // return false;
1107  // }
1108  // }
1109  // }
1110 
1111  if (strcmp(name, MinMaxPositionNP.name) == 0)
1112  {
1113  /* new positions */
1114  double new_min = 0;
1115  double new_max = 0;
1116 
1117  for (nset = i = 0; i < n; i++)
1118  {
1119  /* Find numbers with the passed names in the MinMaxPositionNP property */
1120  INumber *mmpp = IUFindNumber(&MinMaxPositionNP, names[i]);
1121 
1122  /* If the number found is (MinMaxPositionN[0]) then process it */
1123  if (mmpp == &MinMaxPositionN[0])
1124  {
1125  new_min = (values[i]);
1126  nset += static_cast<int>(new_min >= 1 && new_min <= 65000);
1127  }
1128  else if (mmpp == &MinMaxPositionN[1])
1129  {
1130  new_max = (values[i]);
1131  nset += static_cast<int>(new_max >= 1 && new_max <= 65000);
1132  }
1133  }
1134 
1135  /* Did we process the two numbers? */
1136  if (nset == 2)
1137  {
1138  /* Set the robofocus state to BUSY */
1139  MinMaxPositionNP.s = IPS_BUSY;
1140 
1141  currentMinPosition = new_min;
1142  currentMaxPosition = new_max;
1143 
1144  MinMaxPositionNP.s = IPS_OK;
1145  IDSetNumber(&MinMaxPositionNP, "Minimum and Maximum settings are now %3.0f %3.0f", currentMinPosition,
1147  return true;
1148  }
1149  else
1150  {
1151  /* Set property state to idle */
1152  MinMaxPositionNP.s = IPS_IDLE;
1153 
1154  IDSetNumber(&MinMaxPositionNP, "Minimum and maximum limits absent or bogus.");
1155 
1156  return false;
1157  }
1158  }
1159 
1160  if (strcmp(name, MaxTravelNP.name) == 0)
1161  {
1162  double new_maxt = 0;
1163  int ret = -1;
1164 
1165  for (nset = i = 0; i < n; i++)
1166  {
1167  /* Find numbers with the passed names in the MinMaxPositionNP property */
1168  INumber *mmpp = IUFindNumber(&MaxTravelNP, names[i]);
1169 
1170  /* If the number found is (MaxTravelN[0]) then process it */
1171  if (mmpp == &MaxTravelN[0])
1172  {
1173  new_maxt = (values[i]);
1174  nset += static_cast<int>(new_maxt >= 1 && new_maxt <= 64000);
1175  }
1176  }
1177  /* Did we process the one number? */
1178  if (nset == 1)
1179  {
1180  IDSetNumber(&MinMaxPositionNP, nullptr);
1181 
1182  if ((ret = updateRFMaxPosition(&new_maxt)) < 0)
1183  {
1184  MaxTravelNP.s = IPS_IDLE;
1185  IDSetNumber(&MaxTravelNP, "Changing to new maximum travel failed");
1186  return false;
1187  }
1188 
1189  currentMaxTravel = new_maxt;
1190  MaxTravelNP.s = IPS_OK;
1191  IDSetNumber(&MaxTravelNP, "Maximum travel is now %3.0f", currentMaxTravel);
1192  return true;
1193  }
1194  else
1195  {
1196  /* Set property state to idle */
1197 
1198  MaxTravelNP.s = IPS_IDLE;
1199  IDSetNumber(&MaxTravelNP, "Maximum travel absent or bogus.");
1200 
1201  return false;
1202  }
1203  }
1204 
1205  // if (strcmp(name, SetRegisterPositionNP.name) == 0)
1206  // {
1207  // double new_apos = 0;
1208  // int nset = 0;
1209  // int ret = -1;
1210 
1211  // for (nset = i = 0; i < n; i++)
1212  // {
1213  // /* Find numbers with the passed names in the SetRegisterPositionNP property */
1214  // INumber *srpp = IUFindNumber(&SetRegisterPositionNP, names[i]);
1215 
1216  // /* If the number found is SetRegisterPosition (SetRegisterPositionN[0]) then process it */
1217  // if (srpp == &SetRegisterPositionN[0])
1218  // {
1219  // new_apos = (values[i]);
1220 
1221  // /* limits are absolute */
1222  // nset += static_cast<int>(new_apos >= 0 && new_apos <= 64000);
1223  // }
1224 
1225  // if (nset == 1)
1226  // {
1227  // if ((new_apos < currentMinPosition) || (new_apos > currentMaxPosition))
1228  // {
1229  // SetRegisterPositionNP.s = IPS_ALERT;
1230  // IDSetNumber(&SetRegisterPositionNP, "Value out of limits %5.0f", new_apos);
1231  // return false;
1232  // }
1233 
1234  // /* Set the robofocus state to BUSY */
1235  // SetRegisterPositionNP.s = IPS_BUSY;
1236  // IDSetNumber(&SetRegisterPositionNP, nullptr);
1237 
1238  // if ((ret = updateRFSetPosition(&new_apos)) < 0)
1239  // {
1240  // SetRegisterPositionNP.s = IPS_OK;
1241  // IDSetNumber(&SetRegisterPositionNP,
1242  // "Read out of the set position to %3d failed. Trying to recover the position", ret);
1243 
1244  // if ((ret = updateRFPosition(&currentPosition)) < 0)
1245  // {
1246  // FocusAbsPosNP.s = IPS_ALERT;
1247  // IDSetNumber(&FocusAbsPosNP, "Unknown error while reading Robofocus position: %d", ret);
1248 
1249  // SetRegisterPositionNP.s = IPS_IDLE;
1250  // IDSetNumber(&SetRegisterPositionNP, "Relative movement failed.");
1251  // }
1252 
1253  // SetRegisterPositionNP.s = IPS_OK;
1254  // IDSetNumber(&SetRegisterPositionNP, nullptr);
1255 
1256  // FocusAbsPosNP.s = IPS_OK;
1257  // IDSetNumber(&FocusAbsPosNP, "Robofocus position recovered %5.0f", currentPosition);
1258  // LOG_DEBUG("Robofocus position recovered resuming normal operation");
1259  // /* We have to leave here, because new_apos is not set */
1260  // return true;
1261  // }
1262  // currentPosition = new_apos;
1263  // SetRegisterPositionNP.s = IPS_OK;
1264  // IDSetNumber(&SetRegisterPositionNP, "Robofocus register set to %5.0f", currentPosition);
1265 
1266  // FocusAbsPosNP.s = IPS_OK;
1267  // IDSetNumber(&FocusAbsPosNP, "Robofocus position is now %5.0f", currentPosition);
1268 
1269  // return true;
1270  // }
1271  // else
1272  // {
1273  // SetRegisterPositionNP.s = IPS_IDLE;
1274  // IDSetNumber(&SetRegisterPositionNP, "Need exactly one parameter.");
1275 
1276  // return false;
1277  // }
1278 
1279  // if ((ret = updateRFPosition(&currentPosition)) < 0)
1280  // {
1281  // FocusAbsPosNP.s = IPS_ALERT;
1282  // LOGF_ERROR("Unknown error while reading Robofocus position: %d", ret);
1283  // IDSetNumber(&FocusAbsPosNP, nullptr);
1284 
1285  // return false;
1286  // }
1287 
1288  // SetRegisterPositionNP.s = IPS_OK;
1289  // SetRegisterPositionN[0].value = currentPosition;
1290  // IDSetNumber(&SetRegisterPositionNP, "Robofocus has accepted new register setting");
1291 
1292  // FocusAbsPosNP.s = IPS_OK;
1293  // LOGF_INFO("Robofocus new position %5.0f", currentPosition);
1294  // IDSetNumber(&FocusAbsPosNP, nullptr);
1295 
1296  // return true;
1297  // }
1298  // }
1299  }
1300 
1301  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
1302 }
1303 
1304 void RoboFocus::GetFocusParams()
1305 {
1306  int ret = -1;
1307  int cur_s1LL = 0;
1308  int cur_s2LR = 0;
1309  int cur_s3RL = 0;
1310  int cur_s4RR = 0;
1311 
1312  if ((ret = updateRFPosition(&currentPosition)) < 0)
1313  {
1315  LOGF_ERROR("Unknown error while reading Robofocus position: %d", ret);
1316  IDSetNumber(&FocusAbsPosNP, nullptr);
1317  return;
1318  }
1319 
1321  IDSetNumber(&FocusAbsPosNP, nullptr);
1322 
1323  if ((ret = updateRFTemperature(&currentTemperature)) < 0)
1324  {
1325  TemperatureNP.s = IPS_ALERT;
1326  LOG_ERROR("Unknown error while reading Robofocus temperature.");
1327  IDSetNumber(&TemperatureNP, nullptr);
1328  return;
1329  }
1330 
1331  TemperatureNP.s = IPS_OK;
1332  IDSetNumber(&TemperatureNP, nullptr);
1333 
1335  if ((ret = updateRFBacklash(&currentBacklash)) < 0)
1336  {
1338  LOG_ERROR("Unknown error while reading Robofocus backlash.");
1339  IDSetNumber(&FocusBacklashNP, nullptr);
1340  return;
1341  }
1343  IDSetNumber(&FocusBacklashNP, nullptr);
1344 
1346 
1347  if ((ret = updateRFMotorSettings(&currentDuty, &currentDelay, &currentTicks)) < 0)
1348  {
1349  SettingsNP.s = IPS_ALERT;
1350  LOG_ERROR("Unknown error while reading Robofocus motor settings.");
1351  IDSetNumber(&SettingsNP, nullptr);
1352  return;
1353  }
1354 
1355  SettingsNP.s = IPS_OK;
1356  IDSetNumber(&SettingsNP, nullptr);
1357 
1358  if ((ret = updateRFPowerSwitches(-1, -1, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
1359  {
1360  PowerSwitchesSP.s = IPS_ALERT;
1361  LOG_ERROR("Unknown error while reading Robofocus power switch settings.");
1362  IDSetSwitch(&PowerSwitchesSP, nullptr);
1363  return;
1364  }
1365 
1366  PowerSwitchesS[0].s = PowerSwitchesS[1].s = PowerSwitchesS[2].s = PowerSwitchesS[3].s = ISS_OFF;
1367 
1368  if (cur_s1LL == ISS_ON)
1369  {
1370  PowerSwitchesS[0].s = ISS_ON;
1371  }
1372  if (cur_s2LR == ISS_ON)
1373  {
1374  PowerSwitchesS[1].s = ISS_ON;
1375  }
1376  if (cur_s3RL == ISS_ON)
1377  {
1378  PowerSwitchesS[2].s = ISS_ON;
1379  }
1380  if (cur_s4RR == ISS_ON)
1381  {
1382  PowerSwitchesS[3].s = ISS_ON;
1383  }
1384  PowerSwitchesSP.s = IPS_OK;
1385  IDSetSwitch(&PowerSwitchesSP, nullptr);
1386 
1387  // currentMaxTravel = MAXTRAVEL_READOUT;
1388  // if ((ret = updateRFMaxPosition(&currentMaxTravel)) < 0)
1389  // {
1390  // MaxTravelNP.s = IPS_ALERT;
1391  // LOG_ERROR("Unknown error while reading Robofocus maximum travel");
1392  // IDSetNumber(&MaxTravelNP, nullptr);
1393  // return;
1394  // }
1395  // MaxTravelNP.s = IPS_OK;
1396  // IDSetNumber(&MaxTravelNP, nullptr);
1397 }
1398 
1399 IPState RoboFocus::MoveAbsFocuser(uint32_t targetTicks)
1400 {
1401  int ret = -1;
1402  targetPos = targetTicks;
1403 
1404  if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max)
1405  {
1406  LOG_DEBUG("Error, requested position is out of range.");
1407  return IPS_ALERT;
1408  }
1409 
1410  if ((ret = updateRFPositionAbsolute(targetPos)) < 0)
1411  {
1412  LOGF_DEBUG("Read out of the absolute movement failed %3d", ret);
1413  return IPS_ALERT;
1414  }
1415 
1416  RemoveTimer(timerID);
1417  timerID = SetTimer(250);
1418  return IPS_BUSY;
1419 }
1420 
1422 {
1423  return MoveAbsFocuser(FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1)));
1424 }
1425 
1427 {
1428  IUSaveConfigNumber(fp, &SettingsNP);
1430 
1431  return INDI::Focuser::saveConfigItems(fp);
1432 }
1433 
1435 {
1436  if (!isConnected())
1437  return;
1438 
1439  double prevPos = currentPosition;
1440  double newPos = 0;
1441 
1443  {
1444  int rc = updateRFPosition(&newPos);
1445  if (rc >= 0)
1446  {
1447  currentPosition = newPos;
1448  if (prevPos != currentPosition)
1449  IDSetNumber(&FocusAbsPosNP, nullptr);
1450  }
1451  }
1452  else if (FocusAbsPosNP.s == IPS_BUSY)
1453  {
1454  float newPos = 0;
1455  int nbytes_read = 0;
1456  char rf_cmd[RF_MAX_CMD] = { 0 };
1457 
1458  //nbytes_read= ReadUntilComplete(rf_cmd, RF_TIMEOUT) ;
1459 
1460  nbytes_read = ReadResponse(rf_cmd);
1461 
1462  rf_cmd[nbytes_read - 1] = 0;
1463 
1464  if (nbytes_read != 9 || (sscanf(rf_cmd, "FD0%5f", &newPos) <= 0))
1465  {
1467  "Bogus position: (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X) - Bytes read: %d",
1468  rf_cmd[0], rf_cmd[1], rf_cmd[2], rf_cmd[3], rf_cmd[4], rf_cmd[5], rf_cmd[6], rf_cmd[7], rf_cmd[8],
1469  nbytes_read);
1470  timerID = SetTimer(getCurrentPollingPeriod());
1471  return;
1472  }
1473  else if (nbytes_read < 0)
1474  {
1476  LOG_ERROR("Read error! Reconnect and try again.");
1477  IDSetNumber(&FocusAbsPosNP, nullptr);
1478  return;
1479  }
1480 
1481  currentPosition = newPos;
1482 
1483  if (currentPosition == targetPos)
1484  {
1486 
1487  if (FocusRelPosNP.s == IPS_BUSY)
1488  {
1490  IDSetNumber(&FocusRelPosNP, nullptr);
1491  }
1492  }
1493 
1494  IDSetNumber(&FocusAbsPosNP, nullptr);
1495  if (FocusAbsPosNP.s == IPS_BUSY)
1496  {
1497  timerID = SetTimer(250);
1498  return;
1499  }
1500  }
1501 
1502  timerID = SetTimer(getCurrentPollingPeriod());
1503 }
1504 
1506 {
1507  LOG_DEBUG("Aborting focuser...");
1508 
1509  int nbytes_written;
1510  const char *buf = "\r";
1511 
1512  return tty_write(PortFD, buf, strlen(buf), &nbytes_written) == TTY_OK;
1513 }
1514 
1516 {
1517  double value = steps;
1518  return (updateRFBacklash(&value) == 0);
1519 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void addSimulationControl()
Add Simulation control to the driver.
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.
bool isSimulation() const
void RemoveTimer(int id)
Remove timer added with SetTimer.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INumberVectorProperty FocusBacklashNP
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.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: robofocus.cpp:1426
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: robofocus.cpp:1434
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: robofocus.cpp:1421
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition: robofocus.cpp:1505
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: robofocus.cpp:992
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
Definition: robofocus.cpp:1515
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition: robofocus.cpp:865
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: robofocus.cpp:133
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: robofocus.cpp:60
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: robofocus.cpp:1399
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: robofocus.cpp:914
virtual bool Handshake() override
perform handshake with device to check communication
Definition: robofocus.cpp:169
const char * getDefaultName() override
Definition: robofocus.cpp:192
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
double max(void)
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ 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
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
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
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
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indidevapi.c:66
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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 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
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indidevapi.c:76
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOGF_WARN(fmt,...)
Definition: indilogger.h:81
#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 DEBUGF(priority, msg,...)
Definition: indilogger.h:57
#define MAXRBUF
Definition: indiserver.cpp:102
@ value
the parser finished reading a JSON value
#define currentTicks
Definition: robofocus.cpp:42
#define currentDelay
Definition: robofocus.cpp:41
#define currentTemperature
Definition: robofocus.cpp:38
#define RF_TIMEOUT
Definition: robofocus.cpp:31
#define currentMinPosition
Definition: robofocus.cpp:46
#define MAXTRAVEL_READOUT
Definition: robofocus.cpp:34
#define currentMaxTravel
Definition: robofocus.cpp:48
#define RF_MAX_CMD
Definition: robofocus.cpp:30
#define BACKLASH_READOUT
Definition: robofocus.cpp:33
#define currentPosition
Definition: robofocus.cpp:37
#define currentBacklash
Definition: robofocus.cpp:39
#define SETTINGS_TAB
Definition: robofocus.cpp:50
#define currentMaxPosition
Definition: robofocus.cpp:47
#define currentDuty
Definition: robofocus.cpp:40
One number descriptor.
One switch descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371