Instrument Neutral Distributed Interface INDI 2.2.5
myfocuserpro2.cpp
Go to the documentation of this file.
1/*
2 MyFocuserPro2 Focuser
3 Copyright (c) 2019 Alan Townshend
4
5 Based on Moonlite focuser
6 Copyright (C) 2013-2019 Jasem Mutlaq ([email protected])
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22*/
23
24#include "myfocuserpro2.h"
26#include "indicom.h"
27
28#include <cmath>
29#include <cstring>
30#include <memory>
31
32#include <termios.h>
33#include <unistd.h>
34
35static std::unique_ptr<MyFocuserPro2> myFocuserPro2(new MyFocuserPro2());
36
48
50{
52
53 FocusSpeedNP[0].setMin(0);
54 FocusSpeedNP[0].setMax(2);
55 FocusSpeedNP[0].setValue(1);
56
57 /* Relative and absolute movement */
58 FocusRelPosNP[0].setMin(0.);
59 FocusRelPosNP[0].setMax(50000.);
60 FocusRelPosNP[0].setValue(0.);
61 FocusRelPosNP[0].setStep(1000);
62
63 FocusAbsPosNP[0].setMin(0.);
64 FocusAbsPosNP[0].setMax(200000.);
65 FocusAbsPosNP[0].setValue(0.);
66 FocusAbsPosNP[0].setStep(1000);
67
68 FocusMaxPosNP[0].setMin(1024.);
69 FocusMaxPosNP[0].setMax(200000.);
70 FocusMaxPosNP[0].setValue(0.);
71 FocusMaxPosNP[0].setStep(1000);
72
73 //Backlash
74 BacklashInStepsN[0].min = 0;
75 BacklashInStepsN[0].max = 512;
76 BacklashInStepsN[0].value = 0;
77 BacklashInStepsN[0].step = 2;
78
79 BacklashOutStepsN[0].min = 0;
80 BacklashOutStepsN[0].max = 512;
81 BacklashOutStepsN[0].value = 0;
82 BacklashOutStepsN[0].step = 2;
83
84
85 // Backlash In
86 IUFillSwitch(&BacklashInS[INDI_ENABLED], "INDI_ENABLED", "On", ISS_OFF);
87 IUFillSwitch(&BacklashInS[INDI_DISABLED], "INDI_DISABLED", "Off", ISS_ON);
88 IUFillSwitchVector(&BacklashInSP, BacklashInS, 2, getDeviceName(), "BACKLASH_IN_TOGGLE", "Backlash In", SETTINGS_TAB, IP_RW,
90
91 IUFillNumber(&BacklashInStepsN[0], "Steps", "", "%3.0f", 0, 512, 2, 0);
92 IUFillNumberVector(&BacklashInStepsNP, BacklashInStepsN, 1, getDeviceName(), "BACKLASH_IN_VALUE", "Backlash In",
93 SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
94
95 // Backlash Out
96 IUFillSwitch(&BacklashOutS[INDI_ENABLED], "INDI_ENABLED", "On", ISS_OFF);
97 IUFillSwitch(&BacklashOutS[INDI_DISABLED], "INDI_DISABLED", "Off", ISS_ON);
98 IUFillSwitchVector(&BacklashOutSP, BacklashOutS, 2, getDeviceName(), "BACKLASH_OUT_TOGGLE", "Backlash Out", SETTINGS_TAB,
100
101 IUFillNumber(&BacklashOutStepsN[0], "Steps", "", "%3.0f", 0, 512, 2, 0);
102 IUFillNumberVector(&BacklashOutStepsNP, BacklashOutStepsN, 1, getDeviceName(), "BACKLASH_OUT_VALUE", "Backlash Out",
103 SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
104
105 // Focuser temperature
106 IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -40, 80., 0., 0.);
107 IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB,
108 IP_RO, 0, IPS_IDLE);
109
110 // Temperature Settings
111 IUFillNumber(&TemperatureSettingN[0], "Coefficient", "", "%6.2f", 0, 50, 1, 0);
112 IUFillNumberVector(&TemperatureSettingNP, TemperatureSettingN, 1, getDeviceName(), "FOCUS_TEMPERATURE_SETTINGS",
113 "T. Settings", SETTINGS_TAB, IP_RW, 0, IPS_IDLE);
114
115 // Compensate for temperature
116 IUFillSwitch(&TemperatureCompensateS[TEMP_COMPENSATE_ENABLE], "TEMP_COMPENSATE_ENABLE", "Enable", ISS_OFF);
117 IUFillSwitch(&TemperatureCompensateS[TEMP_COMPENSATE_DISABLE], "TEMP_COMPENSATE_DISABLE", "Disable", ISS_ON);
118 IUFillSwitchVector(&TemperatureCompensateSP, TemperatureCompensateS, 2, getDeviceName(), "FOCUS_TEMPERATURE_COMPENSATION",
119 "T. Compensation", SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
120
121 // Add step modes 1/64 to 1/256 for TMC type drivers R Brown June 2021
122 IUFillSwitch(&StepModeS[TWOHUNDREDFIFTYSIX_STEP], "TWOHUNDREDFIFTYSIX_STEP", "1/256 Step", ISS_OFF);
123 IUFillSwitch(&StepModeS[ONEHUNDREDTWENTYEIGHT_STEP], "ONEHUNDREDTWENTYEIGHT_STEP", "1/128 Step", ISS_OFF);
124 IUFillSwitch(&StepModeS[SIXTYFOUR_STEP], "SIXTYFOUR_STEP", "1/64 Step", ISS_OFF);
125 IUFillSwitch(&StepModeS[THIRTYSECOND_STEP], "THIRTYSECOND_STEP", "1/32 Step", ISS_OFF);
126 IUFillSwitch(&StepModeS[SIXTEENTH_STEP], "SIXTEENTH_STEP", "1/16 Step", ISS_OFF);
127 IUFillSwitch(&StepModeS[EIGHTH_STEP], "EIGHTH_STEP", "1/8 Step", ISS_OFF);
128 IUFillSwitch(&StepModeS[QUARTER_STEP], "QUARTER_STEP", "1/4 Step", ISS_OFF);
129 IUFillSwitch(&StepModeS[HALF_STEP], "HALF_STEP", "1/2 Step", ISS_OFF);
130 IUFillSwitch(&StepModeS[FULL_STEP], "FULL_STEP", "Full Step", ISS_OFF);
131 IUFillSwitchVector(&StepModeSP, StepModeS, 9, getDeviceName(), "FOCUS_STEP_MODE", "Step Mode", SETTINGS_TAB, IP_RW,
133
134 IUFillSwitch(&CoilPowerS[COIL_POWER_ON], "COIL_POWER_ON", "On", ISS_OFF);
135 IUFillSwitch(&CoilPowerS[COIL_POWER_OFF], "COIL_POWER_OFF", "Off", ISS_ON);
136 IUFillSwitchVector(&CoilPowerSP, CoilPowerS, 2, getDeviceName(), "FOCUS_COIL_POWER", "Coil Power", SETTINGS_TAB, IP_RW,
137 ISR_1OFMANY, 0,
138 IPS_IDLE);
139
140 IUFillSwitch(&DisplayS[DISPLAY_OFF], "DISPLAY_OFF", "Off", ISS_OFF);
141 IUFillSwitch(&DisplayS[DISPLAY_ON], "DISPLAY_ON", "On", ISS_ON);
142 IUFillSwitchVector(&DisplaySP, DisplayS, 2, getDeviceName(), "FOCUS_DISPLAY", "Display", SETTINGS_TAB, IP_RW, ISR_1OFMANY,
143 0, IPS_IDLE);
144
145
146 IUFillSwitch(&GotoHomeS[0], "GOTO_HOME", "Go", ISS_OFF);
147 IUFillSwitchVector(&GotoHomeSP, GotoHomeS, 1, getDeviceName(), "FOCUS_HOME", "Home", MAIN_CONTROL_TAB, IP_RW,
149
150 setPollingPeriodRange(1000, 30000);
152
153 tcpConnection->setDefaultHost("192.168.4.1");
155
156 return true;
157}
158
160{
162
163 if (isConnected())
164 {
165 defineProperty(&GotoHomeSP);
166 defineProperty(&TemperatureNP);
167 defineProperty(&TemperatureSettingNP);
168 defineProperty(&TemperatureCompensateSP);
169 defineProperty(&BacklashInSP);
170 defineProperty(&BacklashInStepsNP);
171 defineProperty(&BacklashOutSP);
172 defineProperty(&BacklashOutStepsNP);
173 defineProperty(&StepModeSP);
174 defineProperty(&DisplaySP);
175 defineProperty(&CoilPowerSP);
176
177 setTemperatureCelsius();
178
179 LOG_INFO("MyFocuserPro2 parameters updated, focuser ready for use.");
180 }
181 else
182 {
183 deleteProperty(GotoHomeSP.name);
184 deleteProperty(TemperatureNP.name);
185 deleteProperty(TemperatureSettingNP.name);
186 deleteProperty(TemperatureCompensateSP.name);
187 deleteProperty(BacklashInSP.name);
188 deleteProperty(BacklashInStepsNP.name);
189 deleteProperty(BacklashOutSP.name);
190 deleteProperty(BacklashOutStepsNP.name);
191 deleteProperty(StepModeSP.name);
192 deleteProperty(DisplaySP.name);
193 deleteProperty(CoilPowerSP.name);
194 }
195
196 return true;
197}
198
200{
201 if (Ack())
202 {
203 LOG_INFO("MyFocuserPro2 is online. Getting focus parameters...");
204
205 getStartupValues();
206
207 return true;
208 }
209
210 LOG_INFO(
211 "Error retrieving data from MyFocuserPro2, please ensure MyFocuserPro2 controller is powered and the port is correct.");
212 return false;
213}
214
216{
217 return "MyFocuserPro2";
218}
219
220bool MyFocuserPro2::Ack()
221{
222 int nbytes_written = 0, nbytes_read = 0, rc = -1;
223 char errstr[MAXRBUF];
224 char resp[5] = {0};
225 int firmWareVersion = 0;
226
227 tcflush(PortFD, TCIOFLUSH);
228
229 //Try to request the firmware version
230 //Test for success on transmission and response
231 //If either one fails, try again, up to 3 times, waiting 1 sec each time
232 //If that fails, then return false.
233 //If success then check the firmware version
234
235 int numChecks = 0;
236 bool success = false;
237 while(numChecks < 3 && !success)
238 {
239 numChecks++;
240 sleep(1); //wait 1 second between each test.
241
242 bool transmissionSuccess = (rc = tty_write(PortFD, ":03#", 4, &nbytes_written)) == TTY_OK;
243 if(!transmissionSuccess)
244 {
245 tty_error_msg(rc, errstr, MAXRBUF);
246 LOGF_ERROR("Handshake Attempt %i, Connection transmission error: %s.", numChecks, errstr);
247 }
248
249 bool responseSuccess;
251 {
252 responseSuccess = (rc = tty_read(PortFD, resp, 5, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read)) == TTY_OK;
253 }
254 else
255 {
256 // assume TCPIP Connection
257 responseSuccess = (rc = tty_read(PortFD, resp, 5, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read)) == TTY_OK;
258 }
259
260 if(!responseSuccess)
261 {
262 tty_error_msg(rc, errstr, MAXRBUF);
263 LOGF_ERROR("Handshake Attempt %i, updatePosition response error: %s.", numChecks, errstr);
264 }
265 success = transmissionSuccess && responseSuccess;
266 }
267
268 if(!success)
269 {
270 LOG_INFO("Handshake failed after 3 attempts");
271 return false;
272 }
273
274 tcflush(PortFD, TCIOFLUSH);
275
276 rc = sscanf(resp, "F%d#", &firmWareVersion);
277
278 if (rc > 0)
279 {
280 // remove check for firmware => 291, assume user is not using older firmware
281 LOGF_INFO("MyFP2 reported firmware %d", firmWareVersion);
282 LOG_INFO("Connection to focuser is successful.");
283 return true;
284 }
285 else
286 {
287 LOGF_ERROR("Invalid Response: focuser firmware version value (%s)", resp);
288 }
289 return false;
290}
291
292bool MyFocuserPro2::readCoilPowerState()
293{
294 char res[ML_RES] = {0};
295
296 if (sendCommand(":11#", res) == false)
297 {
298 return false;
299 }
300
301 uint32_t temp = 0;
302
303 int rc = sscanf(res, "O%u#", &temp);
304
305 if (rc > 0)
306 {
307 if(temp == 0)
308 {
309 CoilPowerS[COIL_POWER_OFF].s = ISS_ON;
310 }
311 else if (temp == 1)
312 {
313 CoilPowerS[COIL_POWER_ON].s = ISS_ON;
314 }
315 else
316 {
317 LOGF_ERROR("Invalid Response: focuser Coil Power value (%s)", res);
318 return false;
319 }
320 }
321 else
322 {
323 LOGF_ERROR("Unknown error: focuser Coil Power value (%s)", res);
324 return false;
325 }
326 return true;
327}
328
329bool MyFocuserPro2::readReverseDirection()
330{
331 char res[ML_RES] = {0};
332
333 if (sendCommand(":13#", res) == false)
334 return false;
335
336 uint32_t temp = 0;
337
338 int rc = sscanf(res, "R%u#", &temp);
339
340 if (rc > 0)
341 {
342 if(temp == 0)
343 {
345 }
346 else if (temp == 1)
347 {
349 }
350 else
351 {
352 LOGF_ERROR("Invalid Response: focuser Reverse direction value (%s)", res);
353 return false;
354 }
355 }
356 else
357 {
358 LOGF_ERROR("Unknown error: focuser Reverse direction value (%s)", res);
359 return false;
360 }
361 return true;
362}
363
364bool MyFocuserPro2::readStepMode()
365{
366 char res[ML_RES] = {0};
367
368 if (sendCommand(":29#", res) == false)
369 {
370 return false;
371 }
372
373 uint32_t stepmode = 0;
374
375 int rc = sscanf(res, "S%u#", &stepmode);
376
377 if( rc > 0 )
378 {
379 switch( stepmode )
380 {
381 case STEPMODE_FULL:
382 StepModeS[FULL_STEP].s = ISS_ON;
383 break;
384 case STEPMODE_HALF:
385 StepModeS[HALF_STEP].s = ISS_ON;
386 break;
387 case STEPMODE_QUARTER:
388 StepModeS[QUARTER_STEP].s = ISS_ON;
389 break;
390 case STEPMODE_EIGHTH:
391 StepModeS[EIGHTH_STEP].s = ISS_ON;
392 break;
394 StepModeS[SIXTEENTH_STEP].s = ISS_ON;
395 break;
397 StepModeS[THIRTYSECOND_STEP].s = ISS_ON;
398 break;
400 StepModeS[SIXTYFOUR_STEP].s = ISS_ON;
401 break;
403 StepModeS[ONEHUNDREDTWENTYEIGHT_STEP].s = ISS_ON;
404 break;
406 StepModeS[TWOHUNDREDFIFTYSIX_STEP].s = ISS_ON;
407 break;
408 default:
409 LOGF_ERROR("Unknown error: Step mode value (%d)", stepmode);
410 return false;
411 break;
412 }
413 }
414 else
415 {
416 LOGF_ERROR("Unknown error: Step mode value (%s)", res);
417 return false;
418 }
419 return true;
420}
421
422bool MyFocuserPro2::readTemperature()
423{
424 char res[ML_RES] = {0};
425
426 if(!readTempProbeAvailability())
427 return false;
428
429 if (sendCommand(":06#", res) == false)
430 return false;
431
432 double temp = 0;
433 int rc = sscanf(res, "Z%lf#", &temp);
434 if (rc > 0)
435 {
436 TemperatureN[0].value = temp;
437 }
438 else
439 {
440 LOGF_ERROR("Unknown error: focuser temperature value (%s)", res);
441 return false;
442 }
443 return true;
444}
445
446bool MyFocuserPro2::readTempCompensateEnable()
447{
448 char res[ML_RES] = {0};
449
450 if (sendCommand(":24#", res) == false)
451 {
452 return false;
453 }
454
455 uint32_t temp = 0;
456
457 int rc = sscanf(res, "1%u#", &temp);
458
459 if (rc > 0)
460 {
461 if(temp == 0)
462 {
463 TemperatureCompensateS[TEMP_COMPENSATE_DISABLE].s = ISS_ON;
464 }
465 else if (temp == 1)
466 {
467 TemperatureCompensateS[TEMP_COMPENSATE_ENABLE].s = ISS_ON;
468 }
469 else
470 {
471 LOGF_ERROR("Invalid Response: focuser T.Compensate value (%s)", res);
472 return false;
473 }
474 }
475 else
476 {
477 LOGF_ERROR("Unknown error: focuser T.Compensate value (%s)", res);
478 return false;
479 }
480 return true;
481}
482
483
484bool MyFocuserPro2::readPosition()
485{
486 char res[ML_RES] = {0};
487
488 if (sendCommand(":00#", res) == false)
489 {
490 return false;
491 }
492
493 int32_t pos;
494 int rc = sscanf(res, "%*c%d#", &pos);
495
496 if (rc > 0)
497 {
498 FocusAbsPosNP[0].setValue(pos);
499 }
500 else
501 {
502 LOGF_ERROR("Unknown error: focuser position value (%s)", res);
503 return false;
504 }
505 return true;
506}
507
508bool MyFocuserPro2::readTempProbeAvailability()
509{
510 char res[ML_RES] = {0};
511
512 if (sendCommand(":83#", res) == false)
513 {
514 return false;
515 }
516
517 int32_t val;
518 int rc = sscanf(res, "c%d#", &val);
519
520 if (rc > 0)
521 {
522 return val==0 ? false : true;
523 }
524 else
525 {
526 LOGF_ERROR("Unknown error: Temp Probe Availability value (%s). We assume available.", res);
527 }
528
529 return true;
530}
531
532bool MyFocuserPro2::readTemperatureCoefficient()
533{
534 char res[ML_RES] = {0};
535
536 if (sendCommand(":26#", res) == false)
537 {
538 return false;
539 }
540
541 int32_t val;
542 int rc = sscanf(res, "B%d#", &val);
543
544 if (rc > 0)
545 {
546 TemperatureSettingN[0].value = val;
547 }
548 else
549 {
550 LOGF_ERROR("Unknown error: Temperature Coefficient value (%s)", res);
551 return false;
552 }
553 return true;
554}
555
556bool MyFocuserPro2::readSpeed()
557{
558 char res[ML_RES] = {0};
559
560 if (sendCommand(":43#", res) == false)
561 {
562 return false;
563 }
564
565 int speed = 0;
566 int rc = sscanf(res, "C%d#", &speed);
567
568 if (rc > 0)
569 {
570 FocusSpeedNP[0].setValue(speed);
571 }
572 else
573 {
574 LOGF_ERROR("Unknown error: focuser speed value (%s)", res);
575 return false;
576 }
577 return true;
578}
579
580bool MyFocuserPro2::readMaxPos()
581{
582 char res[ML_RES] = {0};
583
584 if (sendCommand(":08#", res) == false)
585 {
586 return false;
587 }
588
589 uint32_t maxPos = 0;
590 int rc = sscanf(res, "M%u#", &maxPos);
591
592 if (rc > 0)
593 {
594 FocusMaxPosNP[0].setValue(maxPos);
595 Focuser::SyncPresets(maxPos);
596 }
597 else
598 {
599 LOGF_ERROR("Unknown error: focuser max position value (%s)", res);
600 return false;
601 }
602 return true;
603}
604
605bool MyFocuserPro2::readBacklashInSteps()
606{
607 char res[ML_RES] = {0};
608
609 if (sendCommand(":78#", res) == false)
610 {
611 return false;
612 }
613
614 uint32_t backlash = 0;
615 int rc = sscanf(res, "6%u#", &backlash);
616
617 if (rc > 0)
618 {
619 BacklashInStepsN[0].value = backlash;
620 }
621 else
622 {
623 BacklashInStepsN[0].value = 0;
624 LOGF_ERROR("Unknown error: focuser Backlash IN value (%s)", res);
625 return false;
626 }
627 return true;
628}
629
630bool MyFocuserPro2::readBacklashInEnabled()
631{
632 char res[ML_RES] = {0};
633
634 if (sendCommand(":74#", res) == false)
635 {
636 return false;
637 }
638
639 uint32_t temp = 0;
640 int rc = sscanf(res, "4%u#", &temp);
641
642 if (rc > 0)
643 {
644 if(temp == 0)
645 {
646 BacklashInS[INDI_DISABLED].s = ISS_ON;
647 }
648 else if (temp == 1)
649 {
650 BacklashInS[INDI_ENABLED].s = ISS_ON;
651 }
652 else
653 {
654 LOGF_ERROR("Unknown Response: focuser Backlash IN enabled (%s)", res);
655 }
656 return false;
657 }
658 else
659 {
660 LOGF_ERROR("Unknown error: focuser Backlash IN enabled (%s)", res);
661 return false;
662 }
663 return true; // fix missing return statement R Brown June 2020
664}
665
666bool MyFocuserPro2::readBacklashOutSteps()
667{
668 char res[ML_RES] = {0};
669
670 if (sendCommand(":80#", res) == false)
671 {
672 return false;
673 }
674
675 uint32_t backlash = 0;
676 int rc = sscanf(res, "7%u#", &backlash);
677
678 if (rc > 0)
679 {
680 BacklashOutStepsN[0].value = backlash;
681 }
682 else
683 {
684 LOGF_ERROR("Unknown error: focuser Backlash OUT value (%s)", res);
685 return false;
686 }
687 return true;
688}
689
690bool MyFocuserPro2::readBacklashOutEnabled()
691{
692 char res[ML_RES] = {0};
693
694 if (sendCommand(":76#", res) == false)
695 {
696 return false;
697 }
698
699 uint32_t temp = 0;
700 int rc = sscanf(res, "5%u#", &temp);
701
702 if (rc > 0)
703 {
704 if(temp == 0)
705 {
706 BacklashOutS[INDI_DISABLED].s = ISS_ON;
707 }
708 else if (temp == 1)
709 {
710 BacklashOutS[INDI_ENABLED].s = ISS_ON;
711 }
712 else
713 {
714 LOGF_ERROR("Unknown response: focuser Backlash OUT enabled (%s)", res);
715 }
716 return false;
717 }
718 else
719 {
720 LOGF_ERROR("Unknown error: focuser Backlash OUT enabled (%s)", res);
721 return false;
722 }
723 return true; // fix missing return statement R Brown June 2020
724}
725
726bool MyFocuserPro2::readDisplayVisible()
727{
728 char res[ML_RES] = {0};
729
730 if (sendCommand(":37#", res) == false)
731 {
732 return false;
733 }
734
735 uint32_t temp = 0;
736
737 int rc = sscanf(res, "D%u#", &temp);
738
739 if (rc > 0)
740 {
741 if(temp == 0)
742 {
743 DisplayS[DISPLAY_OFF].s = ISS_ON;
744 }
745 else if (temp == 1)
746 {
747 DisplayS[DISPLAY_ON].s = ISS_ON;
748 }
749 else
750 {
751 LOGF_ERROR("Invalid Response: focuser Display value (%s)", res);
752 return false;
753 }
754 }
755 else
756 {
757 LOGF_ERROR("Unknown error: focuser Display value (%s)", res);
758 return false;
759 }
760 return true;
761}
762
763bool MyFocuserPro2::isMoving()
764{
765 char res[ML_RES] = {0};
766
767 readPosition(); // Fix for Ekos autofocus
768
769 if (sendCommand(":01#", res) == false)
770 {
771 return false;
772 }
773
774 uint32_t temp = 0;
775
776 int rc = sscanf(res, "I%u#", &temp);
777
778 if (rc > 0)
779 {
780 if(temp == 0)
781 {
782 return false;
783 }
784 else if (temp == 1)
785 {
786 return true;
787 }
788 else
789 {
790 LOGF_ERROR("Invalid Response: focuser isMoving value (%s)", res);
791 return false;
792 }
793 }
794 else
795 {
796 LOGF_ERROR("Unknown error: focuser isMoving value (%s)", res);
797 return false;
798 }
799}
800
801bool MyFocuserPro2::setTemperatureCelsius()
802{
803 char cmd[ML_RES] = {0};
804 snprintf(cmd, ML_RES, ":16#"); // fix R Brown July 2021
805 return sendCommand(cmd);
806}
807
808bool MyFocuserPro2::setTemperatureCoefficient(double coefficient)
809{
810 char cmd[ML_RES] = {0};
811 int coeff = coefficient;
812 snprintf(cmd, ML_RES, ":22%d#", coeff);
813 return sendCommand(cmd);
814}
815
816bool MyFocuserPro2::SyncFocuser(uint32_t ticks)
817{
818 char cmd[ML_RES] = {0};
819 snprintf(cmd, ML_RES, ":31%u#", ticks);
820 return sendCommand(cmd);
821}
822
823bool MyFocuserPro2::MoveFocuser(uint32_t position)
824{
825 char cmd[ML_RES] = {0};
826 if(isMoving())
827 {
828 AbortFocuser();
829 }
830 snprintf(cmd, ML_RES, ":05%u#", position);
831 return sendCommand(cmd);
832}
833
834bool MyFocuserPro2::setBacklashInSteps(int16_t steps)
835{
836 char cmd[ML_RES] = {0};
837 snprintf(cmd, ML_RES, ":77%d#", steps);
838 return sendCommand(cmd);
839}
840
841bool MyFocuserPro2::setBacklashInEnabled(bool enabled)
842{
843 char cmd[ML_RES] = {0};
844 snprintf(cmd, ML_RES, ":73%c#", enabled ? '1' : '0');
845 return sendCommand(cmd);
846}
847
848bool MyFocuserPro2::setBacklashOutSteps(int16_t steps)
849{
850 char cmd[ML_RES] = {0};
851 snprintf(cmd, ML_RES, ":79%d#", steps);
852 return sendCommand(cmd);
853}
854
855bool MyFocuserPro2::setBacklashOutEnabled(bool enabled)
856{
857 char cmd[ML_RES] = {0};
858 snprintf(cmd, ML_RES, ":75%c#", enabled ? '1' : '0');
859 return sendCommand(cmd);
860}
861
862bool MyFocuserPro2::setCoilPowerState(CoilPower enable)
863{
864 char cmd[ML_RES] = {0};
865 //snprintf(cmd, ML_RES, ":12%d#", static_cast<int>(enable));
866 snprintf(cmd, ML_RES, ":12%d#", enable);
867 return sendCommand(cmd);
868}
869
871{
872 char cmd[ML_RES] = {0};
873 snprintf(cmd, ML_RES, ":14%d#", static_cast<int>(enable));
874 return sendCommand(cmd);
875}
876
877bool MyFocuserPro2::setDisplayVisible(DisplayMode enable)
878{
879 char cmd[ML_RES] = {0};
880 snprintf(cmd, ML_RES, ":36%d#", enable);
881 return sendCommand(cmd);
882}
883
884bool MyFocuserPro2::setGotoHome()
885{
886 char cmd[ML_RES] = {0};
887 if(isMoving())
888 {
889 AbortFocuser();
890 }
891 snprintf(cmd, ML_RES, ":28#");
892 return sendCommand(cmd);
893}
894
895bool MyFocuserPro2::setStepMode(FocusStepMode smode)
896{
897 char cmd[ML_RES] = {0};
898 //int setMode = 1 << static_cast<int>(mode);
899 //snprintf(cmd, ML_RES, ":30%d#", setMode); // fix for step modes 64-256 R Brown July 2021
900 int stepmode = 1;
901 switch( smode )
902 {
903 case FULL_STEP:
904 stepmode = 1;
905 break;
906 case HALF_STEP:
907 stepmode = 2;
908 break;
909 case QUARTER_STEP:
910 stepmode = 4;
911 break;
912 case EIGHTH_STEP:
913 stepmode = 8;
914 break;
915 case SIXTEENTH_STEP:
916 stepmode = 16;
917 break;
919 stepmode = 32;
920 break;
921 case SIXTYFOUR_STEP:
922 stepmode = 64;
923 break;
925 stepmode = 128;
926 break;
928 stepmode = 256;
929 break;
930 default:
931 LOGF_ERROR("Invalid step mode: (%d)", smode);
932 return false;
933 break;
934 }
935 snprintf(cmd, ML_RES, ":30%d#", stepmode);
936 return sendCommand(cmd);
937}
938
939bool MyFocuserPro2::setSpeed(uint16_t speed)
940{
941 char cmd[ML_RES] = {0};
942 snprintf(cmd, ML_RES, ":150%d#", speed);
943 return sendCommand(cmd);
944}
945
946bool MyFocuserPro2::setTemperatureCompensation(bool enable)
947{
948 char cmd[ML_RES] = {0};
949 snprintf(cmd, ML_RES, ":23%c#", enable ? '1' : '0');
950 return sendCommand(cmd);
951}
952
953bool MyFocuserPro2::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
954{
955 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
956 {
957 // Focus Step Mode
958 if (strcmp(StepModeSP.name, name) == 0)
959 {
960 int current_mode = IUFindOnSwitchIndex(&StepModeSP);
961
962 IUUpdateSwitch(&StepModeSP, states, names, n);
963
964 int target_mode = IUFindOnSwitchIndex(&StepModeSP);
965
966 if (current_mode == target_mode)
967 {
968 StepModeSP.s = IPS_OK;
969 IDSetSwitch(&StepModeSP, nullptr);
970 }
971
972 bool rc = setStepMode(static_cast<FocusStepMode>(target_mode));
973 if (!rc)
974 {
975 IUResetSwitch(&StepModeSP);
976 StepModeS[current_mode].s = ISS_ON;
977 StepModeSP.s = IPS_ALERT;
978 IDSetSwitch(&StepModeSP, nullptr);
979 return false;
980 }
981
982 StepModeSP.s = IPS_OK;
983 IDSetSwitch(&StepModeSP, nullptr);
984 return true;
985 }
986
987 // Goto Home Position
988 if (strcmp(GotoHomeSP.name, name) == 0)
989 {
990 bool rc = setGotoHome();
991 if (!rc)
992 {
993 IUResetSwitch(&GotoHomeSP);
994 CoilPowerSP.s = IPS_ALERT;
995 IDSetSwitch(&GotoHomeSP, nullptr);
996 return false;
997 }
998
999 GotoHomeSP.s = IPS_OK;
1000 IDSetSwitch(&GotoHomeSP, nullptr);
1001 return true;
1002 }
1003
1004 // Coil Power Mode
1005 if (strcmp(CoilPowerSP.name, name) == 0)
1006 {
1007 int current_mode = IUFindOnSwitchIndex(&CoilPowerSP);
1008
1009 IUUpdateSwitch(&CoilPowerSP, states, names, n);
1010
1011 int target_mode = IUFindOnSwitchIndex(&CoilPowerSP);
1012
1013 if (current_mode == target_mode)
1014 {
1015 CoilPowerSP.s = IPS_OK;
1016 IDSetSwitch(&CoilPowerSP, nullptr);
1017 }
1018
1019 bool rc = setCoilPowerState(static_cast<CoilPower>(target_mode));
1020 if (!rc)
1021 {
1022 IUResetSwitch(&CoilPowerSP);
1023 CoilPowerS[current_mode].s = ISS_ON;
1024 CoilPowerSP.s = IPS_ALERT;
1025 IDSetSwitch(&CoilPowerSP, nullptr);
1026 return false;
1027 }
1028
1029 CoilPowerSP.s = IPS_OK;
1030 IDSetSwitch(&CoilPowerSP, nullptr);
1031 return true;
1032 }
1033
1034 // Display Control
1035 if (strcmp(DisplaySP.name, name) == 0)
1036 {
1037 int current_mode = IUFindOnSwitchIndex(&DisplaySP);
1038
1039 IUUpdateSwitch(&DisplaySP, states, names, n);
1040
1041 int target_mode = IUFindOnSwitchIndex(&DisplaySP);
1042
1043 if (current_mode == target_mode)
1044 {
1045 DisplaySP.s = IPS_OK;
1046 IDSetSwitch(&DisplaySP, nullptr);
1047 }
1048
1049 bool rc = setDisplayVisible(static_cast<DisplayMode>(target_mode));
1050 if (!rc)
1051 {
1052 IUResetSwitch(&DisplaySP);
1053 DisplayS[current_mode].s = ISS_ON;
1054 DisplaySP.s = IPS_ALERT;
1055 IDSetSwitch(&DisplaySP, nullptr);
1056 return false;
1057 }
1058
1059 DisplaySP.s = IPS_OK;
1060 IDSetSwitch(&DisplaySP, nullptr);
1061 return true;
1062 }
1063
1064 // Backlash In Enable
1065 if (strcmp(BacklashInSP.name, name) == 0)
1066 {
1067 int current_mode = IUFindOnSwitchIndex(&BacklashInSP);
1068
1069 IUUpdateSwitch(&BacklashInSP, states, names, n);
1070
1071 int target_mode = IUFindOnSwitchIndex(&BacklashInSP);
1072
1073 if (current_mode == target_mode)
1074 {
1075 BacklashInSP.s = IPS_OK;
1076 IDSetSwitch(&BacklashInSP, nullptr);
1077 }
1078
1079 bool rc = setBacklashInEnabled(target_mode == INDI_ENABLED);
1080 if (!rc)
1081 {
1082 IUResetSwitch(&BacklashInSP);
1083 BacklashInS[current_mode].s = ISS_ON;
1084 BacklashInSP.s = IPS_ALERT;
1085 IDSetSwitch(&BacklashInSP, nullptr);
1086 return false;
1087 }
1088
1089 BacklashInSP.s = IPS_OK;
1090 IDSetSwitch(&BacklashInSP, nullptr);
1091 return true;
1092 }
1093
1094 // Backlash Out Enable
1095 if (strcmp(BacklashOutSP.name, name) == 0)
1096 {
1097 int current_mode = IUFindOnSwitchIndex(&BacklashOutSP);
1098
1099 IUUpdateSwitch(&BacklashOutSP, states, names, n);
1100
1101 int target_mode = IUFindOnSwitchIndex(&BacklashOutSP);
1102
1103 if (current_mode == target_mode)
1104 {
1105 BacklashOutSP.s = IPS_OK;
1106 IDSetSwitch(&BacklashOutSP, nullptr);
1107 }
1108
1109 bool rc = setBacklashOutEnabled(target_mode == INDI_ENABLED);
1110 if (!rc)
1111 {
1112 IUResetSwitch(&BacklashOutSP);
1113 BacklashOutS[current_mode].s = ISS_ON;
1114 BacklashOutSP.s = IPS_ALERT;
1115 IDSetSwitch(&BacklashOutSP, nullptr);
1116 return false;
1117 }
1118
1119 BacklashOutSP.s = IPS_OK;
1120 IDSetSwitch(&BacklashOutSP, nullptr);
1121 return true;
1122 }
1123
1124 // Temperature Compensation Mode
1125 if (strcmp(TemperatureCompensateSP.name, name) == 0)
1126 {
1127 int last_index = IUFindOnSwitchIndex(&TemperatureCompensateSP);
1128 IUUpdateSwitch(&TemperatureCompensateSP, states, names, n);
1129
1130 bool rc = setTemperatureCompensation((TemperatureCompensateS[0].s == ISS_ON));
1131
1132 if (!rc)
1133 {
1134 TemperatureCompensateSP.s = IPS_ALERT;
1135 IUResetSwitch(&TemperatureCompensateSP);
1136 TemperatureCompensateS[last_index].s = ISS_ON;
1137 IDSetSwitch(&TemperatureCompensateSP, nullptr);
1138 return false;
1139 }
1140
1141 TemperatureCompensateSP.s = IPS_OK;
1142 IDSetSwitch(&TemperatureCompensateSP, nullptr);
1143 return true;
1144 }
1145 }
1146
1147 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
1148}
1149
1150bool MyFocuserPro2::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
1151{
1152 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
1153 {
1154 // Temperature Settings
1155 if (strcmp(name, TemperatureSettingNP.name) == 0)
1156 {
1157 IUUpdateNumber(&TemperatureSettingNP, values, names, n);
1158 if (!setTemperatureCoefficient(TemperatureSettingN[0].value))
1159 {
1160 TemperatureSettingNP.s = IPS_ALERT;
1161 IDSetNumber(&TemperatureSettingNP, nullptr);
1162 return false;
1163 }
1164
1165 TemperatureSettingNP.s = IPS_OK;
1166 IDSetNumber(&TemperatureSettingNP, nullptr);
1167 return true;
1168 }
1169
1170 // Backlash In
1171 if (strcmp(name, BacklashInStepsNP.name) == 0)
1172 {
1173 IUUpdateNumber(&BacklashInStepsNP, values, names, n);
1174 if (!setBacklashInSteps(BacklashInStepsN[0].value))
1175 {
1176 BacklashInStepsNP.s = IPS_ALERT;
1177 IDSetNumber(&BacklashInStepsNP, nullptr);
1178 return false;
1179 }
1180
1181 BacklashInStepsNP.s = IPS_OK;
1182 IDSetNumber(&BacklashInStepsNP, nullptr);
1183 return true;
1184 }
1185
1186 // Backlash Out
1187 if (strcmp(name, BacklashOutStepsNP.name) == 0)
1188 {
1189 IUUpdateNumber(&BacklashOutStepsNP, values, names, n);
1190 if (!setBacklashOutSteps(BacklashOutStepsN[0].value))
1191 {
1192 BacklashOutStepsNP.s = IPS_ALERT;
1193 IDSetNumber(&BacklashOutStepsNP, nullptr);
1194 return false;
1195 }
1196
1197 BacklashOutStepsNP.s = IPS_OK;
1198 IDSetNumber(&BacklashOutStepsNP, nullptr);
1199 return true;
1200 }
1201
1202 }
1203
1204 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
1205}
1206
1207void MyFocuserPro2::getStartupValues()
1208{
1209 readMaxPos();
1210 readPosition();
1211 readTemperature();
1212 readTemperatureCoefficient();
1213 readSpeed();
1214 readTempCompensateEnable();
1215 readStepMode();
1216 readCoilPowerState();
1217 readDisplayVisible();
1218 readReverseDirection();
1219 readBacklashInEnabled();
1220 readBacklashOutEnabled();
1221 readBacklashInSteps();
1222 readBacklashOutSteps();
1223}
1224
1226{
1227 return setSpeed(speed);
1228}
1229
1230
1232{
1233 char cmd[ML_RES] = {0};
1234
1235 snprintf(cmd, ML_RES, ":07%06d#", maxPos);
1236
1237 if(sendCommand(cmd))
1238 {
1239 Focuser::SyncPresets(maxPos);
1240 return true;
1241 }
1242 return false;
1243}
1244
1245IPState MyFocuserPro2::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
1246{
1247 if (speed != static_cast<int>(FocusSpeedNP[0].getValue()))
1248 {
1249 if (!setSpeed(speed))
1250 {
1251 return IPS_ALERT;
1252 }
1253 }
1254
1255 // either go all the way in or all the way out
1256 // then use timer to stop
1257 if (dir == FOCUS_INWARD)
1258 {
1259 MoveFocuser(0);
1260 }
1261 else
1262 {
1263 MoveFocuser(FocusMaxPosNP[0].getValue());
1264 }
1265
1267 return IPS_BUSY;
1268}
1269
1271{
1272 static_cast<MyFocuserPro2 *>(context)->timedMoveCallback();
1273}
1274
1275void MyFocuserPro2::timedMoveCallback()
1276{
1277 AbortFocuser();
1281 FocusTimerNP[0].setValue(0);
1285}
1286
1288{
1289 targetPos = targetTicks;
1290
1291 if (!MoveFocuser(targetPos))
1292 {
1293 return IPS_ALERT;
1294 }
1295 return IPS_BUSY;
1296}
1297
1299{
1300 int32_t newPosition = 0;
1301
1302 if (dir == FOCUS_INWARD)
1303 {
1304 newPosition = FocusAbsPosNP[0].getValue() - ticks;
1305 }
1306 else
1307 {
1308 newPosition = FocusAbsPosNP[0].getValue() + ticks;
1309 }
1310
1311 // Clamp
1312 newPosition = std::max(0, std::min(static_cast<int32_t>(FocusAbsPosNP[0].getMax()), newPosition));
1313 if (!MoveFocuser(newPosition))
1314 {
1315 return IPS_ALERT;
1316 }
1317
1318 FocusRelPosNP[0].setValue(ticks);
1320
1321 return IPS_BUSY;
1322}
1323
1324// this is occurring every 500ms
1326{
1327 if (!isConnected())
1328 {
1330 return;
1331 }
1332
1333 // update position every 1s
1334 if (Position_Counter++ == GET_POSITION_FREQ)
1335 {
1336 //LOG_INFO("Focuser refresh position.");
1337 Position_Counter = 0;
1338 bool rc = readPosition();
1339 if (rc)
1340 {
1341 if (fabs(lastPos - FocusAbsPosNP[0].getValue()) > 5)
1342 {
1344 lastPos = FocusAbsPosNP[0].getValue();
1345 }
1346 }
1348 {
1349 if (!isMoving())
1350 {
1355 lastPos = FocusAbsPosNP[0].getValue();
1356 LOG_INFO("Focuser reached requested position.");
1357 }
1358 }
1359 }
1360
1362 {
1363 if (!isMoving())
1364 {
1369 lastPos = FocusAbsPosNP[0].getValue();
1370 LOG_INFO("Focuser reached requested position.");
1371 }
1372 }
1373
1374 // update temperature every 5s
1375 if (Temperature_Counter++ == GET_TEMPERATURE_FREQ)
1376 {
1377 //LOG_INFO("Focuser refresh Temperature.");
1378 Temperature_Counter = 0;
1379 bool rc = readTemperature();
1380 if (rc)
1381 {
1382 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
1383 {
1384 IDSetNumber(&TemperatureNP, nullptr);
1385 lastTemperature = TemperatureN[0].value;
1386 }
1387 }
1388 }
1390}
1391
1393{
1394 return sendCommand(":27#");
1395}
1396
1398{
1399 Focuser::saveConfigItems(fp);
1400
1401 IUSaveConfigNumber(fp, &TemperatureSettingNP);
1402 IUSaveConfigSwitch(fp, &TemperatureCompensateSP);
1403 IUSaveConfigSwitch(fp, &BacklashInSP);
1404 IUSaveConfigNumber(fp, &BacklashInStepsNP);
1405 IUSaveConfigSwitch(fp, &BacklashOutSP);
1406 IUSaveConfigNumber(fp, &BacklashOutStepsNP);
1407 IUSaveConfigSwitch(fp, &StepModeSP);
1408 IUSaveConfigSwitch(fp, &DisplaySP);
1409
1410 return true;
1411}
1412
1413// sleep for a number of milliseconds
1414int MyFocuserPro2::msleep( long duration)
1415{
1416 struct timespec ts;
1417 int res;
1418
1419 if (duration < 0)
1420 {
1421 errno = EINVAL;
1422 return -1;
1423 }
1424
1425 ts.tv_sec = duration / 1000;
1426 ts.tv_nsec = (duration % 1000) * 1000000;
1427
1428 do
1429 {
1430 res = nanosleep(&ts, &ts);
1431 }
1432 while (res && errno == EINTR);
1433
1434 return res;
1435}
1436
1437void MyFocuserPro2::clearbufferonerror()
1438{
1439 bool rc;
1440 char res[ML_RES] = {0};
1441 int nbytes_read = 0;
1442
1443 // if the driver and controller get out of sync, this is an attempt to recover from that situation
1444 // attempt to clear the receive buffer if the controller response arrived after a serial timeout
1445 pthread_mutex_lock(&cmdlock);
1446 msleep(MYFOCUSERPRO2_RECOVER_DELAY);
1448 {
1449 rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read);
1450 }
1451 else
1452 {
1453 // assume TCP/IP Connection
1454 rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read);
1455 }
1456 pthread_mutex_unlock(&cmdlock);
1457 if( rc != TTY_OK)
1458 {
1459 //LOGF_ERROR("No data read from controller");
1460 }
1461 else
1462 {
1463 LOGF_ERROR("Data read from controller: %s.", res);
1464 }
1465}
1466
1467bool MyFocuserPro2::sendCommand(const char * cmd, char * res)
1468{
1469 int nbytes_written = 0, nbytes_read = 0, rc = -1;
1470
1471 tcflush(PortFD, TCIOFLUSH);
1472
1473 LOGF_DEBUG("CMD <%s>", cmd);
1474
1475 pthread_mutex_lock(&cmdlock);
1476 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
1477 {
1478 char errstr[MAXRBUF] = {0};
1479 tty_error_msg(rc, errstr, MAXRBUF);
1480 LOGF_ERROR("Connection write error: %s.", errstr);
1481 pthread_mutex_unlock(&cmdlock);
1482 return false;
1483 }
1484
1485 if (res == nullptr)
1486 {
1487 tcdrain(PortFD);
1488 pthread_mutex_unlock(&cmdlock);
1489 return true;
1490 }
1491 //pthread_mutex_unlock(&cmdlock);
1492
1493 // sleep for 20ms to give time for controller to process command before attempting to read reply
1494 msleep(MYFOCUSERPRO2_SMALL_DELAY);
1495
1496 //pthread_mutex_lock(&cmdlock);
1497 // replace ML_TIMEOUT, needs to be dependant on connection type
1499 {
1500 rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read);
1501 }
1502 else
1503 {
1504 // assume TCP/IP Connection
1505 rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read);
1506 }
1507
1508 if (rc != TTY_OK)
1509 {
1510 char errstr[MAXRBUF] = {0};
1511 tty_error_msg(rc, errstr, MAXRBUF);
1512 LOGF_ERROR("Connection read error: %s.", errstr);
1513 pthread_mutex_unlock(&cmdlock);
1514 return false;
1515 }
1516
1517 LOGF_DEBUG("RES <%s>", res);
1518
1519 tcflush(PortFD, TCIOFLUSH);
1520 pthread_mutex_unlock(&cmdlock);
1521 return true;
1522}
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
bool isConnected() const
void setPollingPeriodRange(uint32_t minimum, uint32_t maximum)
setPollingPeriodRange Set the range permitted by the polling range in milliseconds
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Connection::Interface * getActiveConnection()
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusTimerNP
INDI::PropertyNumber FocusMaxPosNP
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 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,...
Connection::TCP * tcpConnection
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 setSupportedConnections(const uint8_t &value)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
virtual bool saveConfigItems(FILE *fp) override
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser Move focuser in a specific direction and speed for period of time.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
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 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 SyncFocuser(uint32_t ticks) override
SyncFocuser Set the supplied position as the current focuser position.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
virtual bool Handshake() override
Handshake Try to communicate with Focuser and see if there is a valid response.
static void timedMoveHelper(void *context)
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
const char * getDefaultName() override
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition eventloop.c:586
int errno
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
@ ISR_ATMOST1
Definition indiapi.h:172
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
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:759
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
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
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition indidevapi.c:337
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
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
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
#define STEPMODE_THIRTYSECOND
#define STEPMODE_ONEHUNDREDTWENTYEIGHT
#define CDRIVER_VERSION_MAJOR
#define STEPMODE_QUARTER
#define STEPMODE_SIXTEENTH
#define STEPMODE_FULL
#define CDRIVER_VERSION_MINOR
#define STEPMODE_SIXTYFOUR
#define STEPMODE_HALF
#define STEPMODE_TWOHUNDREDFIFTYSIX
#define STEPMODE_EIGHTH
uint16_t type
Definition pwc-ioctl.h:0
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:321
char name[MAXINDINAME]
Definition indiapi.h:369