Instrument Neutral Distributed Interface INDI 2.2.5
robofocus.cpp
Go to the documentation of this file.
1/*
2 RoboFocus
3 Copyright (C) 2006 Markus Wildi ([email protected])
4 2011 Jasem Mutlaq ([email protected])
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 currentDuty SettingsN[0].value
37#define currentDelay SettingsN[1].value
38#define currentTicks SettingsN[2].value
39#define currentMaxTravel MaxTravelN[0].value
40#define currentMinPosition MinMaxPositionN[0].value
41#define currentMaxPosition MinMaxPositionN[1].value
42
43
44#define SETTINGS_TAB "Settings"
45
46static std::unique_ptr<RoboFocus> roboFocus(new RoboFocus());
47
53
55{
57
58 /* Focuser temperature */
59 IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", 0, 65000., 0., 10000.);
60 IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
62
63 /* Settings of the Robofocus */
64 IUFillNumber(&SettingsN[0], "Duty cycle", "Duty cycle", "%6.0f", 0., 255., 0., 1.0);
65 IUFillNumber(&SettingsN[1], "Step Delay", "Step delay", "%6.0f", 0., 255., 0., 1.0);
66 IUFillNumber(&SettingsN[2], "Motor Steps", "Motor steps per tick", "%6.0f", 0., 255., 0., 1.0);
67 IUFillNumberVector(&SettingsNP, SettingsN, 3, getDeviceName(), "FOCUS_SETTINGS", "Settings", SETTINGS_TAB, IP_RW, 0,
68 IPS_IDLE);
69
70 /* Power Switches of the Robofocus */
71 IUFillSwitch(&PowerSwitchesS[0], "1", "Switch 1", ISS_OFF);
72 IUFillSwitch(&PowerSwitchesS[1], "2", "Switch 2", ISS_OFF);
73 IUFillSwitch(&PowerSwitchesS[2], "3", "Switch 3", ISS_OFF);
74 IUFillSwitch(&PowerSwitchesS[3], "4", "Switch 4", ISS_ON);
75 IUFillSwitchVector(&PowerSwitchesSP, PowerSwitchesS, 4, getDeviceName(), "SWITCHES", "Power", SETTINGS_TAB, IP_RW,
77
78 /* Robofocus should stay within these limits */
79 IUFillNumber(&MinMaxPositionN[0], "MINPOS", "Minimum Tick", "%6.0f", 1., 65000., 0., 100.);
80 IUFillNumber(&MinMaxPositionN[1], "MAXPOS", "Maximum Tick", "%6.0f", 1., 65000., 0., 55000.);
81 IUFillNumberVector(&MinMaxPositionNP, MinMaxPositionN, 2, getDeviceName(), "FOCUS_MINMAXPOSITION", "Extrema",
83
84 IUFillNumber(&MaxTravelN[0], "MAXTRAVEL", "Maximum travel", "%6.0f", 1., 64000., 0., 10000.);
85 IUFillNumberVector(&MaxTravelNP, MaxTravelN, 1, getDeviceName(), "FOCUS_MAXTRAVEL", "Max. travel", SETTINGS_TAB,
86 IP_RW, 0, IPS_IDLE);
87
88 // Cannot change maximum position
90 FocusMaxPosNP[0].setValue(64000);
91
92 FocusBacklashNP[0].setMin(-255);
93 FocusBacklashNP[0].setMax(255);
94 FocusBacklashNP[0].setStep(10);
95 FocusBacklashNP[0].setValue(0);
96
97 /* Relative and absolute movement */
98 FocusRelPosNP[0].setMin(0.);
99 FocusRelPosNP[0].setMax(5000.);
100 FocusRelPosNP[0].setValue(100);
101 FocusRelPosNP[0].setStep(100);
102
103 FocusAbsPosNP[0].setMin(0.);
104 FocusAbsPosNP[0].setMax(64000.);
105 FocusAbsPosNP[0].setValue(0);
106 FocusAbsPosNP[0].setStep(1000);
107
108 simulatedTemperature = 600.0;
109 simulatedPosition = 20000;
110
113
114 return true;
115}
116
118{
120
121 if (isConnected())
122 {
123 defineProperty(&TemperatureNP);
124 defineProperty(&PowerSwitchesSP);
125 defineProperty(&SettingsNP);
126 defineProperty(&MinMaxPositionNP);
127 defineProperty(&MaxTravelNP);
128 GetFocusParams();
129
130 LOG_DEBUG("RoboFocus parameters readout complete, focuser ready for use.");
131 }
132 else
133 {
134 deleteProperty(TemperatureNP.name);
135 deleteProperty(SettingsNP.name);
136 deleteProperty(PowerSwitchesSP.name);
137 deleteProperty(MinMaxPositionNP.name);
138 deleteProperty(MaxTravelNP.name);
139 }
140
141 return true;
142}
143
145{
146 char firmeware[] = "FV0000000";
147
148 if (isSimulation())
149 {
151 LOG_INFO("Simulated Robofocus is online. Getting focus parameters...");
152 FocusAbsPosNP[0].setValue(simulatedPosition);
153 updateRFFirmware(firmeware);
154 return true;
155 }
156
157 if ((updateRFFirmware(firmeware)) < 0)
158 {
159 /* This would be the end*/
160 LOG_ERROR("Unknown error while reading Robofocus firmware.");
161 return false;
162 }
163
164 return true;
165}
166
168{
169 return "RoboFocus";
170}
171
172unsigned char RoboFocus::CheckSum(char *rf_cmd)
173{
174 char substr[255];
175 unsigned char val = 0;
176
177 for (int i = 0; i < 8; i++)
178 substr[i] = rf_cmd[i];
179
180 val = CalculateSum(substr);
181
182 if (val != (unsigned char)rf_cmd[8])
183 LOGF_WARN("Checksum: Wrong (%s,%ld), %x != %x", rf_cmd, strlen(rf_cmd), val,
184 (unsigned char)rf_cmd[8]);
185
186 return val;
187}
188
189unsigned char RoboFocus::CalculateSum(const char *rf_cmd)
190{
191 unsigned char val = 0;
192
193 for (int i = 0; i < 8; i++)
194 val = val + (unsigned char)rf_cmd[i];
195
196 return val % 256;
197}
198
199int RoboFocus::SendCommand(char *rf_cmd)
200{
201 int nbytes_written = 0, err_code = 0;
202 char rf_cmd_cks[32], robofocus_error[MAXRBUF];
203
204 unsigned char val = 0;
205
206 val = CalculateSum(rf_cmd);
207
208 for (int i = 0; i < 8; i++)
209 rf_cmd_cks[i] = rf_cmd[i];
210
211 rf_cmd_cks[8] = (unsigned char)val;
212 rf_cmd_cks[9] = 0;
213
214 if (isSimulation())
215 return 0;
216
217 tcflush(PortFD, TCIOFLUSH);
218
219 LOGF_DEBUG("CMD (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X)", rf_cmd_cks[0],
220 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],
221 rf_cmd_cks[8]);
222
223 if ((err_code = tty_write(PortFD, rf_cmd_cks, RF_MAX_CMD, &nbytes_written) != TTY_OK))
224 {
225 tty_error_msg(err_code, robofocus_error, MAXRBUF);
226 LOGF_ERROR("TTY error detected: %s", robofocus_error);
227 return -1;
228 }
229
230 return nbytes_written;
231}
232
233int RoboFocus::ReadResponse(char *buf)
234{
235 char robofocus_error[MAXRBUF];
236 char robofocus_char[1];
237 int bytesRead = 0;
238 int err_code;
239
240 char motion = 0;
241 bool externalMotion = false;
242
243 if (isSimulation())
244 return RF_MAX_CMD;
245
246 while (true)
247 {
248 if ((err_code = tty_read(PortFD, robofocus_char, 1, RF_TIMEOUT, &bytesRead)) != 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 switch (robofocus_char[0])
256 {
257 // Catch 'I'
258 case 0x49:
259 if (motion != 0x49)
260 {
261 motion = 0x49;
262 LOG_INFO("Moving inward...");
263
265 {
266 externalMotion = true;
269 }
270 }
271 //usleep(100000);
272 break;
273
274 // catch 'O'
275 case 0x4F:
276 if (motion != 0x4F)
277 {
278 motion = 0x4F;
279 LOG_INFO("Moving outward...");
280
282 {
283 externalMotion = true;
286 }
287 }
288 //usleep(100000);
289 break;
290
291 // Start of frame
292 case 0x46:
293 buf[0] = 0x46;
294 // Read rest of frame
295 if ((err_code = tty_read(PortFD, buf + 1, RF_MAX_CMD - 1, RF_TIMEOUT, &bytesRead)) != TTY_OK)
296 {
297 tty_error_msg(err_code, robofocus_error, MAXRBUF);
298 LOGF_ERROR("TTY error detected: %s", robofocus_error);
299 return -1;
300 }
301
302 if (motion != 0)
303 {
304 LOG_INFO("Stopped.");
305
306 // If we set it busy due to external motion, let's set it to OK
307 if (externalMotion)
308 {
311 }
312 }
313
314 tcflush(PortFD, TCIOFLUSH);
315 return (bytesRead + 1);
316 break;
317
318 default:
319 break;
320 }
321 }
322
323 return -1;
324}
325
326int RoboFocus::updateRFPosition(double *value)
327{
328 float temp;
329 char rf_cmd[RF_MAX_CMD];
330 int robofocus_rc;
331
332 LOG_DEBUG("Querying Position...");
333
334 if (isSimulation())
335 {
336 *value = simulatedPosition;
337 return 0;
338 }
339
340 strncpy(rf_cmd, "FG000000", 9);
341
342 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
343 return robofocus_rc;
344
345 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
346 return robofocus_rc;
347
348 if (sscanf(rf_cmd, "FD%6f", &temp) < 1)
349 return -1;
350
351 *value = (double)temp;
352
353 LOGF_DEBUG("Position: %g", *value);
354
355 return 0;
356}
357
358int RoboFocus::updateRFTemperature(double *value)
359{
360 LOGF_DEBUG("Update Temperature: %g", value);
361
362 float temp;
363 char rf_cmd[32];
364 int robofocus_rc;
365
366 strncpy(rf_cmd, "FT000000", 9);
367
368 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
369 return robofocus_rc;
370
371 if (isSimulation())
372 snprintf(rf_cmd, 32, "FT%6g", simulatedTemperature);
373 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
374 return robofocus_rc;
375
376 if (sscanf(rf_cmd, "FT%6f", &temp) < 1)
377 return -1;
378
379 *value = (double)temp / 2. - 273.15;
380
381 return 0;
382}
383
384int RoboFocus::updateRFBacklash(double *value)
385{
386 LOGF_DEBUG("Update Backlash: %g", value);
387
388 float temp;
389 char rf_cmd[32];
390 char vl_tmp[4];
391 int robofocus_rc;
392 int sign = 0;
393
394 if (isSimulation())
395 {
396 *value = FocusBacklashNP[0].getValue();
397 return 0;
398 }
399
400 if (*value == BACKLASH_READOUT)
401 {
402 strncpy(rf_cmd, "FB000000", 9);
403 }
404 else
405 {
406 rf_cmd[0] = 'F';
407 rf_cmd[1] = 'B';
408
409 if (*value > 0)
410 {
411 rf_cmd[2] = '3';
412 }
413 else
414 {
415 *value = -*value;
416 rf_cmd[2] = '2';
417 }
418 rf_cmd[3] = '0';
419 rf_cmd[4] = '0';
420
421 if (*value > 99)
422 {
423 sprintf(vl_tmp, "%3d", (int)*value);
424 }
425 else if (*value > 9)
426 {
427 sprintf(vl_tmp, "0%2d", (int)*value);
428 }
429 else
430 {
431 sprintf(vl_tmp, "00%1d", (int)*value);
432 }
433 rf_cmd[5] = vl_tmp[0];
434 rf_cmd[6] = vl_tmp[1];
435 rf_cmd[7] = vl_tmp[2];
436 }
437
438 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
439 return robofocus_rc;
440
441 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
442 return robofocus_rc;
443
444 if (sscanf(rf_cmd, "FB%1d%5f", &sign, &temp) < 1)
445 return -1;
446
447 *value = (double)temp;
448
449 if ((sign == 2) && (*value > 0))
450 {
451 *value = -(*value);
452 }
453
454 return 0;
455}
456
457int RoboFocus::updateRFFirmware(char *rf_cmd)
458{
459 int robofocus_rc;
460
461 LOG_DEBUG("Querying RoboFocus Firmware...");
462
463 strncpy(rf_cmd, "FV000000", 9);
464
465 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
466 return robofocus_rc;
467
468 if (isSimulation())
469 strncpy(rf_cmd, "SIM", 4);
470 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
471 return robofocus_rc;
472
473 return 0;
474}
475
476int RoboFocus::updateRFMotorSettings(double *duty, double *delay, double *ticks)
477{
478 LOGF_DEBUG("Update Motor Settings: Duty (%g), Delay (%g), Ticks(%g)", *duty, *delay, *ticks);
479
480 char rf_cmd[32];
481 int robofocus_rc;
482
483 if (isSimulation())
484 {
485 *duty = 100;
486 *delay = 0;
487 *ticks = 0;
488 return 0;
489 }
490
491 if ((*duty == 0) && (*delay == 0) && (*ticks == 0))
492 {
493 strncpy(rf_cmd, "FC000000", 9);
494 }
495 else
496 {
497 rf_cmd[0] = 'F';
498 rf_cmd[1] = 'C';
499 rf_cmd[2] = (char) * duty;
500 rf_cmd[3] = (char) * delay;
501 rf_cmd[4] = (char) * ticks;
502 rf_cmd[5] = '0';
503 rf_cmd[6] = '0';
504 rf_cmd[7] = '0';
505 rf_cmd[8] = 0;
506 }
507
508 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
509 return robofocus_rc;
510
511 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
512 return robofocus_rc;
513
514 *duty = (float)rf_cmd[2];
515 *delay = (float)rf_cmd[3];
516 *ticks = (float)rf_cmd[4];
517
518 return 0;
519}
520
521int RoboFocus::updateRFPositionRelativeInward(double value)
522{
523 char rf_cmd[32];
524 int robofocus_rc;
525 //float temp ;
526 rf_cmd[0] = 0;
527
528 LOGF_DEBUG("Update Relative Position Inward: %g", value);
529
530 if (isSimulation())
531 {
532 simulatedPosition += value;
533 //value = simulatedPosition;
534 return 0;
535 }
536
537 if (value > 9999)
538 {
539 sprintf(rf_cmd, "FI0%5d", (int)value);
540 }
541 else if (value > 999)
542 {
543 sprintf(rf_cmd, "FI00%4d", (int)value);
544 }
545 else if (value > 99)
546 {
547 sprintf(rf_cmd, "FI000%3d", (int)value);
548 }
549 else if (value > 9)
550 {
551 sprintf(rf_cmd, "FI0000%2d", (int)value);
552 }
553 else
554 {
555 sprintf(rf_cmd, "FI00000%1d", (int)value);
556 }
557
558 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
559 return robofocus_rc;
560
561 return 0;
562}
563
564int RoboFocus::updateRFPositionRelativeOutward(double value)
565{
566 char rf_cmd[32];
567 int robofocus_rc;
568 //float temp ;
569
570 LOGF_DEBUG("Update Relative Position Outward: %g", value);
571
572 if (isSimulation())
573 {
574 simulatedPosition -= value;
575 //value = simulatedPosition;
576 return 0;
577 }
578
579 rf_cmd[0] = 0;
580
581 if (value > 9999)
582 {
583 sprintf(rf_cmd, "FO0%5d", (int)value);
584 }
585 else if (value > 999)
586 {
587 sprintf(rf_cmd, "FO00%4d", (int)value);
588 }
589 else if (value > 99)
590 {
591 sprintf(rf_cmd, "FO000%3d", (int)value);
592 }
593 else if (value > 9)
594 {
595 sprintf(rf_cmd, "FO0000%2d", (int)value);
596 }
597 else
598 {
599 sprintf(rf_cmd, "FO00000%1d", (int)value);
600 }
601
602 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
603 return robofocus_rc;
604
605 return 0;
606}
607
608int RoboFocus::updateRFPositionAbsolute(double value)
609{
610 char rf_cmd[32];
611 int robofocus_rc;
612
613 LOGF_DEBUG("Moving Absolute Position: %g", value);
614
615 if (isSimulation())
616 {
617 simulatedPosition = value;
618 return 0;
619 }
620
621 rf_cmd[0] = 0;
622
623 if (value > 9999)
624 {
625 sprintf(rf_cmd, "FG0%5d", (int)value);
626 }
627 else if (value > 999)
628 {
629 sprintf(rf_cmd, "FG00%4d", (int)value);
630 }
631 else if (value > 99)
632 {
633 sprintf(rf_cmd, "FG000%3d", (int)value);
634 }
635 else if (value > 9)
636 {
637 sprintf(rf_cmd, "FG0000%2d", (int)value);
638 }
639 else
640 {
641 sprintf(rf_cmd, "FG00000%1d", (int)value);
642 }
643
644 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
645 return robofocus_rc;
646
647 return 0;
648}
649
650int RoboFocus::updateRFPowerSwitches(int s, int new_sn, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR)
651{
652 INDI_UNUSED(s);
653 char rf_cmd[32];
654 char rf_cmd_tmp[32];
655 int robofocus_rc;
656 int i = 0;
657
658 if (isSimulation())
659 {
660 return 0;
661 }
662
663 LOG_DEBUG("Get switch status...");
664
665 /* Get first the status */
666 strncpy(rf_cmd_tmp, "FP000000", 9);
667
668 if ((robofocus_rc = SendCommand(rf_cmd_tmp)) < 0)
669 return robofocus_rc;
670
671 if ((robofocus_rc = ReadResponse(rf_cmd_tmp)) < 0)
672 return robofocus_rc;
673
674 for (i = 0; i < 9; i++)
675 {
676 rf_cmd[i] = rf_cmd_tmp[i];
677 }
678
679 if (rf_cmd[new_sn + 4] == '2')
680 {
681 rf_cmd[new_sn + 4] = '1';
682 }
683 else
684 {
685 rf_cmd[new_sn + 4] = '2';
686 }
687
688 rf_cmd[8] = 0;
689
690 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
691 return robofocus_rc;
692
693 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
694 return robofocus_rc;
695
696 *cur_s1LL = *cur_s2LR = *cur_s3RL = *cur_s4RR = ISS_OFF;
697
698 if (rf_cmd[4] == '2')
699 {
700 *cur_s1LL = ISS_ON;
701 }
702
703 if (rf_cmd[5] == '2')
704 {
705 *cur_s2LR = ISS_ON;
706 }
707
708 if (rf_cmd[6] == '2')
709 {
710 *cur_s3RL = ISS_ON;
711 }
712
713 if (rf_cmd[7] == '2')
714 {
715 *cur_s4RR = ISS_ON;
716 }
717 return 0;
718}
719
720int RoboFocus::updateRFMaxPosition(double *value)
721{
722 LOG_DEBUG("Query max position...");
723
724 float temp;
725 char rf_cmd[32];
726 char vl_tmp[6];
727 int robofocus_rc;
728 char waste[1];
729
730 if (isSimulation())
731 {
732 return 0;
733 }
734
735 if (*value == MAXTRAVEL_READOUT)
736 {
737 strncpy(rf_cmd, "FL000000", 9);
738 }
739 else
740 {
741 rf_cmd[0] = 'F';
742 rf_cmd[1] = 'L';
743 rf_cmd[2] = '0';
744
745 if (*value > 9999)
746 {
747 sprintf(vl_tmp, "%5d", (int)*value);
748 }
749 else if (*value > 999)
750 {
751 sprintf(vl_tmp, "0%4d", (int)*value);
752 }
753 else if (*value > 99)
754 {
755 sprintf(vl_tmp, "00%3d", (int)*value);
756 }
757 else if (*value > 9)
758 {
759 sprintf(vl_tmp, "000%2d", (int)*value);
760 }
761 else
762 {
763 sprintf(vl_tmp, "0000%1d", (int)*value);
764 }
765 rf_cmd[3] = vl_tmp[0];
766 rf_cmd[4] = vl_tmp[1];
767 rf_cmd[5] = vl_tmp[2];
768 rf_cmd[6] = vl_tmp[3];
769 rf_cmd[7] = vl_tmp[4];
770 rf_cmd[8] = 0;
771 }
772
773 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
774 return robofocus_rc;
775
776 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
777 return robofocus_rc;
778
779 if (sscanf(rf_cmd, "FL%1c%5f", waste, &temp) < 1)
780 return -1;
781
782 *value = (double)temp;
783
784 LOGF_DEBUG("Max position: %g", *value);
785
786 return 0;
787}
788
789bool RoboFocus::SyncFocuser(uint32_t ticks)
790{
791 char rf_cmd[32];
792 char vl_tmp[6];
793 int ret_read_tmp;
794
795 if (isSimulation())
796 {
797 FocusAbsPosNP[0].setValue(ticks);
798 return true;
799 }
800
801 rf_cmd[0] = 'F';
802 rf_cmd[1] = 'S';
803 rf_cmd[2] = '0';
804
805 if (ticks > 9999)
806 {
807 snprintf(vl_tmp, 6, "%5d", ticks);
808 }
809 else if (ticks > 999)
810 {
811 snprintf(vl_tmp, 6, "0%4d", ticks);
812 }
813 else if (ticks > 99)
814 {
815 snprintf(vl_tmp, 6, "00%3d", ticks);
816 }
817 else if (ticks > 9)
818 {
819 snprintf(vl_tmp, 6, "000%2d", ticks);
820 }
821 else
822 {
823 snprintf(vl_tmp, 6, "0000%1d", ticks);
824 }
825 rf_cmd[3] = vl_tmp[0];
826 rf_cmd[4] = vl_tmp[1];
827 rf_cmd[5] = vl_tmp[2];
828 rf_cmd[6] = vl_tmp[3];
829 rf_cmd[7] = vl_tmp[4];
830 rf_cmd[8] = 0;
831
832 if ((ret_read_tmp = SendCommand(rf_cmd)) < 0)
833 return false;
834
835 return true;
836}
837
838bool RoboFocus::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
839{
840 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
841 {
842 if (strcmp(name, PowerSwitchesSP.name) == 0)
843 {
844 int ret = -1;
845 int nset = 0;
846 int i = 0;
847 int new_s = -1;
848 int new_sn = -1;
849 int cur_s1LL = 0;
850 int cur_s2LR = 0;
851 int cur_s3RL = 0;
852 int cur_s4RR = 0;
853
854 ISwitch *sp;
855
856 PowerSwitchesSP.s = IPS_BUSY;
857 IDSetSwitch(&PowerSwitchesSP, nullptr);
858
859 for (nset = i = 0; i < n; i++)
860 {
861 /* Find numbers with the passed names in the SettingsNP property */
862 sp = IUFindSwitch(&PowerSwitchesSP, names[i]);
863
864 /* If the state found is (PowerSwitchesS[0]) then process it */
865
866 if (sp == &PowerSwitchesS[0])
867 {
868 new_s = (states[i]);
869 new_sn = 0;
870 nset++;
871 }
872 else if (sp == &PowerSwitchesS[1])
873 {
874 new_s = (states[i]);
875 new_sn = 1;
876 nset++;
877 }
878 else if (sp == &PowerSwitchesS[2])
879 {
880 new_s = (states[i]);
881 new_sn = 2;
882 nset++;
883 }
884 else if (sp == &PowerSwitchesS[3])
885 {
886 new_s = (states[i]);
887 new_sn = 3;
888 nset++;
889 }
890 }
891 if (nset == 1)
892 {
893 cur_s1LL = cur_s2LR = cur_s3RL = cur_s4RR = 0;
894
895 if ((ret = updateRFPowerSwitches(new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
896 {
897 PowerSwitchesSP.s = IPS_ALERT;
898 IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading Robofocus power switch settings");
899 return true;
900 }
901 }
902 else
903 {
904 /* Set property state to idle */
905 PowerSwitchesSP.s = IPS_IDLE;
906
907 IDSetNumber(&SettingsNP, "Power switch settings absent or bogus.");
908 return true;
909 }
910 }
911 }
912
913 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
914}
915
916bool RoboFocus::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
917{
918 int nset = 0, i = 0;
919
920 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
921 {
922 if (strcmp(name, SettingsNP.name) == 0)
923 {
924 /* new speed */
925 double new_duty = 0;
926 double new_delay = 0;
927 double new_ticks = 0;
928 int ret = -1;
929
930 for (nset = i = 0; i < n; i++)
931 {
932 /* Find numbers with the passed names in the SettingsNP property */
933 INumber *eqp = IUFindNumber(&SettingsNP, names[i]);
934
935 /* If the number found is (SettingsN[0]) then process it */
936 if (eqp == &SettingsN[0])
937 {
938 new_duty = (values[i]);
939 nset += static_cast<int>(new_duty >= 0 && new_duty <= 255);
940 }
941 else if (eqp == &SettingsN[1])
942 {
943 new_delay = (values[i]);
944 nset += static_cast<int>(new_delay >= 0 && new_delay <= 255);
945 }
946 else if (eqp == &SettingsN[2])
947 {
948 new_ticks = (values[i]);
949 nset += static_cast<int>(new_ticks >= 0 && new_ticks <= 255);
950 }
951 }
952
953 /* Did we process the three numbers? */
954 if (nset == 3)
955 {
956 /* Set the robofocus state to BUSY */
957 SettingsNP.s = IPS_BUSY;
958
959 IDSetNumber(&SettingsNP, nullptr);
960
961 if ((ret = updateRFMotorSettings(&new_duty, &new_delay, &new_ticks)) < 0)
962 {
963 IDSetNumber(&SettingsNP, "Changing to new settings failed");
964 return false;
965 }
966
967 currentDuty = new_duty;
968 currentDelay = new_delay;
969 currentTicks = new_ticks;
970
971 SettingsNP.s = IPS_OK;
972 IDSetNumber(&SettingsNP, "Motor settings are now %3.0f %3.0f %3.0f", currentDuty, currentDelay,
974 return true;
975 }
976 else
977 {
978 /* Set property state to idle */
979 SettingsNP.s = IPS_IDLE;
980
981 IDSetNumber(&SettingsNP, "Settings absent or bogus.");
982 return false;
983 }
984 }
985
986 if (strcmp(name, MinMaxPositionNP.name) == 0)
987 {
988 /* new positions */
989 double new_min = 0;
990 double new_max = 0;
991
992 for (nset = i = 0; i < n; i++)
993 {
994 /* Find numbers with the passed names in the MinMaxPositionNP property */
995 INumber *mmpp = IUFindNumber(&MinMaxPositionNP, names[i]);
996
997 /* If the number found is (MinMaxPositionN[0]) then process it */
998 if (mmpp == &MinMaxPositionN[0])
999 {
1000 new_min = (values[i]);
1001 nset += static_cast<int>(new_min >= 1 && new_min <= 65000);
1002 }
1003 else if (mmpp == &MinMaxPositionN[1])
1004 {
1005 new_max = (values[i]);
1006 nset += static_cast<int>(new_max >= 1 && new_max <= 65000);
1007 }
1008 }
1009
1010 /* Did we process the two numbers? */
1011 if (nset == 2)
1012 {
1013 /* Set the robofocus state to BUSY */
1014 MinMaxPositionNP.s = IPS_BUSY;
1015
1016 currentMinPosition = new_min;
1017 currentMaxPosition = new_max;
1018
1019 MinMaxPositionNP.s = IPS_OK;
1020 IDSetNumber(&MinMaxPositionNP, "Minimum and Maximum settings are now %3.0f %3.0f", currentMinPosition,
1022 return true;
1023 }
1024 else
1025 {
1026 /* Set property state to idle */
1027 MinMaxPositionNP.s = IPS_IDLE;
1028
1029 IDSetNumber(&MinMaxPositionNP, "Minimum and maximum limits absent or bogus.");
1030
1031 return false;
1032 }
1033 }
1034
1035 if (strcmp(name, MaxTravelNP.name) == 0)
1036 {
1037 double new_maxt = 0;
1038 int ret = -1;
1039
1040 for (nset = i = 0; i < n; i++)
1041 {
1042 /* Find numbers with the passed names in the MinMaxPositionNP property */
1043 INumber *mmpp = IUFindNumber(&MaxTravelNP, names[i]);
1044
1045 /* If the number found is (MaxTravelN[0]) then process it */
1046 if (mmpp == &MaxTravelN[0])
1047 {
1048 new_maxt = (values[i]);
1049 nset += static_cast<int>(new_maxt >= 1 && new_maxt <= 64000);
1050 }
1051 }
1052 /* Did we process the one number? */
1053 if (nset == 1)
1054 {
1055 IDSetNumber(&MinMaxPositionNP, nullptr);
1056
1057 if ((ret = updateRFMaxPosition(&new_maxt)) < 0)
1058 {
1059 MaxTravelNP.s = IPS_IDLE;
1060 IDSetNumber(&MaxTravelNP, "Changing to new maximum travel failed");
1061 return false;
1062 }
1063
1064 currentMaxTravel = new_maxt;
1065 MaxTravelNP.s = IPS_OK;
1066 IDSetNumber(&MaxTravelNP, "Maximum travel is now %3.0f", currentMaxTravel);
1067 return true;
1068 }
1069 else
1070 {
1071 /* Set property state to idle */
1072
1073 MaxTravelNP.s = IPS_IDLE;
1074 IDSetNumber(&MaxTravelNP, "Maximum travel absent or bogus.");
1075
1076 return false;
1077 }
1078 }
1079 }
1080
1081 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
1082}
1083
1084void RoboFocus::GetFocusParams()
1085{
1086 int ret = -1;
1087 int cur_s1LL = 0;
1088 int cur_s2LR = 0;
1089 int cur_s3RL = 0;
1090 int cur_s4RR = 0;
1091
1092 double currentPosition = 0;
1093 if ((ret = updateRFPosition(&currentPosition)) < 0)
1094 {
1096 LOGF_ERROR("Unknown error while reading Robofocus position: %d", ret);
1098 return;
1099 }
1100
1101 FocusAbsPosNP[0].setValue(currentPosition);
1104
1105 double currentTemperature = 0;
1106
1107
1108 if ((ret = updateRFTemperature(&currentTemperature)) < 0)
1109 {
1110 TemperatureNP.s = IPS_ALERT;
1111 LOG_ERROR("Unknown error while reading Robofocus temperature.");
1112 IDSetNumber(&TemperatureNP, nullptr);
1113 return;
1114 }
1115
1116 TemperatureN[0].value = currentTemperature;
1117 TemperatureNP.s = IPS_OK;
1118 IDSetNumber(&TemperatureNP, nullptr);
1119
1120 double currentBacklash = 0;
1121
1122 FocusBacklashNP[0].setValue(BACKLASH_READOUT);
1123 if ((ret = updateRFBacklash(&currentBacklash)) < 0)
1124 {
1126 LOG_ERROR("Unknown error while reading Robofocus backlash.");
1128 return;
1129 }
1130 FocusBacklashNP[0].setValue(currentBacklash);
1133
1135
1136 if ((ret = updateRFMotorSettings(&currentDuty, &currentDelay, &currentTicks)) < 0)
1137 {
1138 SettingsNP.s = IPS_ALERT;
1139 LOG_ERROR("Unknown error while reading Robofocus motor settings.");
1140 IDSetNumber(&SettingsNP, nullptr);
1141 return;
1142 }
1143
1144 SettingsNP.s = IPS_OK;
1145 IDSetNumber(&SettingsNP, nullptr);
1146
1147 if ((ret = updateRFPowerSwitches(-1, -1, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
1148 {
1149 PowerSwitchesSP.s = IPS_ALERT;
1150 LOG_ERROR("Unknown error while reading Robofocus power switch settings.");
1151 IDSetSwitch(&PowerSwitchesSP, nullptr);
1152 return;
1153 }
1154
1155 PowerSwitchesS[0].s = PowerSwitchesS[1].s = PowerSwitchesS[2].s = PowerSwitchesS[3].s = ISS_OFF;
1156
1157 if (cur_s1LL == ISS_ON)
1158 {
1159 PowerSwitchesS[0].s = ISS_ON;
1160 }
1161 if (cur_s2LR == ISS_ON)
1162 {
1163 PowerSwitchesS[1].s = ISS_ON;
1164 }
1165 if (cur_s3RL == ISS_ON)
1166 {
1167 PowerSwitchesS[2].s = ISS_ON;
1168 }
1169 if (cur_s4RR == ISS_ON)
1170 {
1171 PowerSwitchesS[3].s = ISS_ON;
1172 }
1173 PowerSwitchesSP.s = IPS_OK;
1174 IDSetSwitch(&PowerSwitchesSP, nullptr);
1175}
1176
1178{
1179 int ret = -1;
1180 targetPos = targetTicks;
1181
1182 if (targetTicks < FocusAbsPosNP[0].getMin() || targetTicks > FocusAbsPosNP[0].getMax())
1183 {
1184 LOG_DEBUG("Error, requested position is out of range.");
1185 return IPS_ALERT;
1186 }
1187
1188 if ((ret = updateRFPositionAbsolute(targetPos)) < 0)
1189 {
1190 LOGF_DEBUG("Read out of the absolute movement failed %3d", ret);
1191 return IPS_ALERT;
1192 }
1193
1194 RemoveTimer(timerID);
1195 timerID = SetTimer(250);
1196 return IPS_BUSY;
1197}
1198
1200{
1201 return MoveAbsFocuser(FocusAbsPosNP[0].getValue() + (ticks * (dir == FOCUS_INWARD ? -1 : 1)));
1202}
1203
1205{
1206 IUSaveConfigNumber(fp, &SettingsNP);
1208
1210}
1211
1213{
1214 if (!isConnected())
1215 return;
1216
1217 double prevPos = FocusAbsPosNP[0].getValue();
1218 double newPos = 0;
1219
1221 {
1222 int rc = updateRFPosition(&newPos);
1223 if (rc >= 0)
1224 {
1225 FocusAbsPosNP[0].setValue(newPos);
1226 if (prevPos != FocusAbsPosNP[0].getValue())
1228 }
1229 }
1230 else if (FocusAbsPosNP.getState() == IPS_BUSY)
1231 {
1232 float newPos = 0;
1233 int nbytes_read = 0;
1234 char rf_cmd[RF_MAX_CMD] = { 0 };
1235
1236 //nbytes_read= ReadUntilComplete(rf_cmd, RF_TIMEOUT) ;
1237
1238 nbytes_read = ReadResponse(rf_cmd);
1239
1240 rf_cmd[nbytes_read - 1] = 0;
1241
1242 if (nbytes_read != 9 || (sscanf(rf_cmd, "FD0%5f", &newPos) <= 0))
1243 {
1245 "Bogus position: (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X) - Bytes read: %d",
1246 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],
1247 nbytes_read);
1248 timerID = SetTimer(getCurrentPollingPeriod());
1249 return;
1250 }
1251 else if (nbytes_read < 0)
1252 {
1254 LOG_ERROR("Read error! Reconnect and try again.");
1256 return;
1257 }
1258
1259 FocusAbsPosNP[0].setValue(newPos);
1260
1261 if (FocusAbsPosNP[0].getValue() == targetPos)
1262 {
1264
1266 {
1269 }
1270 }
1271
1274 {
1275 timerID = SetTimer(250);
1276 return;
1277 }
1278 }
1279
1280 timerID = SetTimer(getCurrentPollingPeriod());
1281}
1282
1284{
1285 LOG_DEBUG("Aborting focuser...");
1286
1287 int nbytes_written;
1288 const char *buf = "\r";
1289
1290 return tty_write(PortFD, buf, strlen(buf), &nbytes_written) == TTY_OK;
1291}
1292
1294{
1295 double value = steps;
1296 return (updateRFBacklash(&value) == 0);
1297}
bool isConnected() const
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.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusBacklashNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool saveConfigItems(FILE *fp) override
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
void setPermission(IPerm permission)
virtual bool saveConfigItems(FILE *fp) override
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition robofocus.cpp:54
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
const char * getDefaultName() override
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
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:490
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition indidevapi.c:275
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition indidevapi.c:285
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition indidevapi.c:23
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:376
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:398
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:453
#define INDI_UNUSED(x)
Definition indidevapi.h:132
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
#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 getDeviceName
#define currentTicks
Definition robofocus.cpp:38
#define currentDelay
Definition robofocus.cpp:37
#define RF_TIMEOUT
Definition robofocus.cpp:31
#define currentMinPosition
Definition robofocus.cpp:40
#define MAXTRAVEL_READOUT
Definition robofocus.cpp:34
#define currentMaxTravel
Definition robofocus.cpp:39
#define RF_MAX_CMD
Definition robofocus.cpp:30
#define BACKLASH_READOUT
Definition robofocus.cpp:33
#define SETTINGS_TAB
Definition robofocus.cpp:44
#define currentMaxPosition
Definition robofocus.cpp:41
#define currentDuty
Definition robofocus.cpp:36
One number descriptor.
One switch descriptor.
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369