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