Instrument Neutral Distributed Interface INDI  2.0.2
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 (mutlaqja@ikarustech.com)
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 
35 static std::unique_ptr<MyFocuserPro2> myFocuserPro2(new MyFocuserPro2());
36 
38 {
39  // Can move in Absolute & Relative motions, can AbortFocuser motion, and has variable speed.
43 
45 
47 }
48 
50 {
52 
53  FocusSpeedN[0].min = 0;
54  FocusSpeedN[0].max = 2;
55  FocusSpeedN[0].value = 1;
56 
57  /* Relative and absolute movement */
58  FocusRelPosN[0].min = 0.;
59  FocusRelPosN[0].max = 50000.;
60  FocusRelPosN[0].value = 0.;
61  FocusRelPosN[0].step = 1000;
62 
63  FocusAbsPosN[0].min = 0.;
64  FocusAbsPosN[0].max = 200000.;
65  FocusAbsPosN[0].value = 0.;
66  FocusAbsPosN[0].step = 1000;
67 
68  FocusMaxPosN[0].min = 1024.;
69  FocusMaxPosN[0].max = 200000.;
70  FocusMaxPosN[0].value = 0.;
71  FocusMaxPosN[0].step = 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,
89  ISR_1OFMANY, 0, IPS_IDLE);
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,
132  ISR_1OFMANY, 0, IPS_IDLE);
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,
148  ISR_ATMOST1, 0, IPS_IDLE);
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 
220 bool 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 firmare => 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 
292 bool 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 
329 bool 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 
364 bool 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;
393  case STEPMODE_SIXTEENTH:
394  StepModeS[SIXTEENTH_STEP].s = ISS_ON;
395  break;
397  StepModeS[THIRTYSECOND_STEP].s = ISS_ON;
398  break;
399  case STEPMODE_SIXTYFOUR:
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 
422 bool MyFocuserPro2::readTemperature()
423 {
424  char res[ML_RES] = {0};
425 
426  if (sendCommand(":06#", res) == false)
427  return false;
428 
429  double temp = 0;
430  int rc = sscanf(res, "Z%lf#", &temp);
431  if (rc > 0)
432  {
433  TemperatureN[0].value = temp;
434  }
435  else
436  {
437  LOGF_ERROR("Unknown error: focuser temperature value (%s)", res);
438  return false;
439  }
440  return true;
441 }
442 
443 bool MyFocuserPro2::readTempCompensateEnable()
444 {
445  char res[ML_RES] = {0};
446 
447  if (sendCommand(":24#", res) == false)
448  {
449  return false;
450  }
451 
452  uint32_t temp = 0;
453 
454  int rc = sscanf(res, "1%u#", &temp);
455 
456  if (rc > 0)
457  {
458  if(temp == 0)
459  {
460  TemperatureCompensateS[TEMP_COMPENSATE_DISABLE].s = ISS_ON;
461  }
462  else if (temp == 1)
463  {
464  TemperatureCompensateS[TEMP_COMPENSATE_ENABLE].s = ISS_ON;
465  }
466  else
467  {
468  LOGF_ERROR("Invalid Response: focuser T.Compensate value (%s)", res);
469  return false;
470  }
471  }
472  else
473  {
474  LOGF_ERROR("Unknown error: focuser T.Compensate value (%s)", res);
475  return false;
476  }
477  return true;
478 }
479 
480 
481 bool MyFocuserPro2::readPosition()
482 {
483  char res[ML_RES] = {0};
484 
485  if (sendCommand(":00#", res) == false)
486  {
487  return false;
488  }
489 
490  int32_t pos;
491  int rc = sscanf(res, "%*c%d#", &pos);
492 
493  if (rc > 0)
494  {
495  FocusAbsPosN[0].value = pos;
496  }
497  else
498  {
499  LOGF_ERROR("Unknown error: focuser position value (%s)", res);
500  return false;
501  }
502  return true;
503 }
504 
505 bool MyFocuserPro2::readTemperatureCoefficient()
506 {
507  char res[ML_RES] = {0};
508 
509  if (sendCommand(":26#", res) == false)
510  {
511  return false;
512  }
513 
514  int32_t val;
515  int rc = sscanf(res, "B%d#", &val);
516 
517  if (rc > 0)
518  {
519  TemperatureSettingN[0].value = val;
520  }
521  else
522  {
523  LOGF_ERROR("Unknown error: Temperature Coefficient value (%s)", res);
524  return false;
525  }
526  return true;
527 }
528 
529 bool MyFocuserPro2::readSpeed()
530 {
531  char res[ML_RES] = {0};
532 
533  if (sendCommand(":43#", res) == false)
534  {
535  return false;
536  }
537 
538  int speed = 0;
539  int rc = sscanf(res, "C%d#", &speed);
540 
541  if (rc > 0)
542  {
543  FocusSpeedN[0].value = speed;
544  }
545  else
546  {
547  LOGF_ERROR("Unknown error: focuser speed value (%s)", res);
548  return false;
549  }
550  return true;
551 }
552 
553 bool MyFocuserPro2::readMaxPos()
554 {
555  char res[ML_RES] = {0};
556 
557  if (sendCommand(":08#", res) == false)
558  {
559  return false;
560  }
561 
562  uint32_t maxPos = 0;
563  int rc = sscanf(res, "M%u#", &maxPos);
564 
565  if (rc > 0)
566  {
567  FocusMaxPosN[0].value = maxPos;
568  Focuser::SyncPresets(maxPos);
569  }
570  else
571  {
572  LOGF_ERROR("Unknown error: focuser max position value (%s)", res);
573  return false;
574  }
575  return true;
576 }
577 
578 bool MyFocuserPro2::readBacklashInSteps()
579 {
580  char res[ML_RES] = {0};
581 
582  if (sendCommand(":78#", res) == false)
583  {
584  return false;
585  }
586 
587  uint32_t backlash = 0;
588  int rc = sscanf(res, "6%u#", &backlash);
589 
590  if (rc > 0)
591  {
592  BacklashInStepsN[0].value = backlash;
593  }
594  else
595  {
596  BacklashInStepsN[0].value = 0;
597  LOGF_ERROR("Unknown error: focuser Backlash IN value (%s)", res);
598  return false;
599  }
600  return true;
601 }
602 
603 bool MyFocuserPro2::readBacklashInEnabled()
604 {
605  char res[ML_RES] = {0};
606 
607  if (sendCommand(":74#", res) == false)
608  {
609  return false;
610  }
611 
612  uint32_t temp = 0;
613  int rc = sscanf(res, "4%u#", &temp);
614 
615  if (rc > 0)
616  {
617  if(temp == 0)
618  {
619  BacklashInS[INDI_DISABLED].s = ISS_ON;
620  }
621  else if (temp == 1)
622  {
623  BacklashInS[INDI_ENABLED].s = ISS_ON;
624  }
625  else
626  {
627  LOGF_ERROR("Unknown Response: focuser Backlash IN enabled (%s)", res);
628  }
629  return false;
630  }
631  else
632  {
633  LOGF_ERROR("Unknown error: focuser Backlash IN enabled (%s)", res);
634  return false;
635  }
636  return true; // fix missing return statement R Brown June 2020
637 }
638 
639 bool MyFocuserPro2::readBacklashOutSteps()
640 {
641  char res[ML_RES] = {0};
642 
643  if (sendCommand(":80#", res) == false)
644  {
645  return false;
646  }
647 
648  uint32_t backlash = 0;
649  int rc = sscanf(res, "7%u#", &backlash);
650 
651  if (rc > 0)
652  {
653  BacklashOutStepsN[0].value = backlash;
654  }
655  else
656  {
657  LOGF_ERROR("Unknown error: focuser Backlash OUT value (%s)", res);
658  return false;
659  }
660  return true;
661 }
662 
663 bool MyFocuserPro2::readBacklashOutEnabled()
664 {
665  char res[ML_RES] = {0};
666 
667  if (sendCommand(":76#", res) == false)
668  {
669  return false;
670  }
671 
672  uint32_t temp = 0;
673  int rc = sscanf(res, "5%u#", &temp);
674 
675  if (rc > 0)
676  {
677  if(temp == 0)
678  {
679  BacklashOutS[INDI_DISABLED].s = ISS_ON;
680  }
681  else if (temp == 1)
682  {
683  BacklashOutS[INDI_ENABLED].s = ISS_ON;
684  }
685  else
686  {
687  LOGF_ERROR("Unknown response: focuser Backlash OUT enabled (%s)", res);
688  }
689  return false;
690  }
691  else
692  {
693  LOGF_ERROR("Unknown error: focuser Backlash OUT enabled (%s)", res);
694  return false;
695  }
696  return true; // fix missing return statement R Brown June 2020
697 }
698 
699 bool MyFocuserPro2::readDisplayVisible()
700 {
701  char res[ML_RES] = {0};
702 
703  if (sendCommand(":37#", res) == false)
704  {
705  return false;
706  }
707 
708  uint32_t temp = 0;
709 
710  int rc = sscanf(res, "D%u#", &temp);
711 
712  if (rc > 0)
713  {
714  if(temp == 0)
715  {
716  DisplayS[DISPLAY_OFF].s = ISS_ON;
717  }
718  else if (temp == 1)
719  {
720  DisplayS[DISPLAY_ON].s = ISS_ON;
721  }
722  else
723  {
724  LOGF_ERROR("Invalid Response: focuser Display value (%s)", res);
725  return false;
726  }
727  }
728  else
729  {
730  LOGF_ERROR("Unknown error: focuser Display value (%s)", res);
731  return false;
732  }
733  return true;
734 }
735 
736 bool MyFocuserPro2::isMoving()
737 {
738  char res[ML_RES] = {0};
739 
740  if (sendCommand(":01#", res) == false)
741  {
742  return false;
743  }
744 
745  uint32_t temp = 0;
746 
747  int rc = sscanf(res, "I%u#", &temp);
748 
749  if (rc > 0)
750  {
751  if(temp == 0)
752  {
753  return false;
754  }
755  else if (temp == 1)
756  {
757  return true;
758  }
759  else
760  {
761  LOGF_ERROR("Invalid Response: focuser isMoving value (%s)", res);
762  return false;
763  }
764  }
765  else
766  {
767  LOGF_ERROR("Unknown error: focuser isMoving value (%s)", res);
768  return false;
769  }
770 }
771 
772 bool MyFocuserPro2::setTemperatureCelsius()
773 {
774  char cmd[ML_RES] = {0};
775  snprintf(cmd, ML_RES, ":16#"); // fix R Brown July 2021
776  return sendCommand(cmd);
777 }
778 
779 bool MyFocuserPro2::setTemperatureCoefficient(double coefficient)
780 {
781  char cmd[ML_RES] = {0};
782  int coeff = coefficient;
783  snprintf(cmd, ML_RES, ":22%d#", coeff);
784  return sendCommand(cmd);
785 }
786 
787 bool MyFocuserPro2::SyncFocuser(uint32_t ticks)
788 {
789  char cmd[ML_RES] = {0};
790  snprintf(cmd, ML_RES, ":31%u#", ticks);
791  return sendCommand(cmd);
792 }
793 
794 bool MyFocuserPro2::MoveFocuser(uint32_t position)
795 {
796  char cmd[ML_RES] = {0};
797  if(isMoving())
798  {
799  AbortFocuser();
800  }
801  snprintf(cmd, ML_RES, ":05%u#", position);
802  return sendCommand(cmd);
803 }
804 
805 bool MyFocuserPro2::setBacklashInSteps(int16_t steps)
806 {
807  char cmd[ML_RES] = {0};
808  snprintf(cmd, ML_RES, ":77%d#", steps);
809  return sendCommand(cmd);
810 }
811 
812 bool MyFocuserPro2::setBacklashInEnabled(bool enabled)
813 {
814  char cmd[ML_RES] = {0};
815  snprintf(cmd, ML_RES, ":73%c#", enabled ? '1' : '0');
816  return sendCommand(cmd);
817 }
818 
819 bool MyFocuserPro2::setBacklashOutSteps(int16_t steps)
820 {
821  char cmd[ML_RES] = {0};
822  snprintf(cmd, ML_RES, ":79%d#", steps);
823  return sendCommand(cmd);
824 }
825 
826 bool MyFocuserPro2::setBacklashOutEnabled(bool enabled)
827 {
828  char cmd[ML_RES] = {0};
829  snprintf(cmd, ML_RES, ":75%c#", enabled ? '1' : '0');
830  return sendCommand(cmd);
831 }
832 
833 bool MyFocuserPro2::setCoilPowerState(CoilPower enable)
834 {
835  char cmd[ML_RES] = {0};
836  //snprintf(cmd, ML_RES, ":12%d#", static_cast<int>(enable));
837  snprintf(cmd, ML_RES, ":12%d#", enable);
838  return sendCommand(cmd);
839 }
840 
842 {
843  char cmd[ML_RES] = {0};
844  snprintf(cmd, ML_RES, ":14%d#", static_cast<int>(enable));
845  return sendCommand(cmd);
846 }
847 
848 bool MyFocuserPro2::setDisplayVisible(DisplayMode enable)
849 {
850  char cmd[ML_RES] = {0};
851  snprintf(cmd, ML_RES, ":36%d#", enable);
852  return sendCommand(cmd);
853 }
854 
855 bool MyFocuserPro2::setGotoHome()
856 {
857  char cmd[ML_RES] = {0};
858  if(isMoving())
859  {
860  AbortFocuser();
861  }
862  snprintf(cmd, ML_RES, ":28#");
863  return sendCommand(cmd);
864 }
865 
866 bool MyFocuserPro2::setStepMode(FocusStepMode smode)
867 {
868  char cmd[ML_RES] = {0};
869  //int setMode = 1 << static_cast<int>(mode);
870  //snprintf(cmd, ML_RES, ":30%d#", setMode); // fix for step modes 64-256 R Brown July 2021
871  int stepmode = 1;
872  switch( smode )
873  {
874  case FULL_STEP:
875  stepmode = 1;
876  break;
877  case HALF_STEP:
878  stepmode = 2;
879  break;
880  case QUARTER_STEP:
881  stepmode = 4;
882  break;
883  case EIGHTH_STEP:
884  stepmode = 8;
885  break;
886  case SIXTEENTH_STEP:
887  stepmode = 16;
888  break;
889  case THIRTYSECOND_STEP:
890  stepmode = 32;
891  break;
892  case SIXTYFOUR_STEP:
893  stepmode = 64;
894  break;
896  stepmode = 128;
897  break;
899  stepmode = 256;
900  break;
901  default:
902  LOGF_ERROR("Invalid step mode: (%d)", smode);
903  return false;
904  break;
905  }
906  snprintf(cmd, ML_RES, ":30%d#", stepmode);
907  return sendCommand(cmd);
908 }
909 
910 bool MyFocuserPro2::setSpeed(uint16_t speed)
911 {
912  char cmd[ML_RES] = {0};
913  snprintf(cmd, ML_RES, ":150%d#", speed);
914  return sendCommand(cmd);
915 }
916 
917 bool MyFocuserPro2::setTemperatureCompensation(bool enable)
918 {
919  char cmd[ML_RES] = {0};
920  snprintf(cmd, ML_RES, ":23%c#", enable ? '1' : '0');
921  return sendCommand(cmd);
922 }
923 
924 bool MyFocuserPro2::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
925 {
926  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
927  {
928  // Focus Step Mode
929  if (strcmp(StepModeSP.name, name) == 0)
930  {
931  int current_mode = IUFindOnSwitchIndex(&StepModeSP);
932 
933  IUUpdateSwitch(&StepModeSP, states, names, n);
934 
935  int target_mode = IUFindOnSwitchIndex(&StepModeSP);
936 
937  if (current_mode == target_mode)
938  {
939  StepModeSP.s = IPS_OK;
940  IDSetSwitch(&StepModeSP, nullptr);
941  }
942 
943  bool rc = setStepMode(static_cast<FocusStepMode>(target_mode));
944  if (!rc)
945  {
946  IUResetSwitch(&StepModeSP);
947  StepModeS[current_mode].s = ISS_ON;
948  StepModeSP.s = IPS_ALERT;
949  IDSetSwitch(&StepModeSP, nullptr);
950  return false;
951  }
952 
953  StepModeSP.s = IPS_OK;
954  IDSetSwitch(&StepModeSP, nullptr);
955  return true;
956  }
957 
958  // Goto Home Position
959  if (strcmp(GotoHomeSP.name, name) == 0)
960  {
961  bool rc = setGotoHome();
962  if (!rc)
963  {
964  IUResetSwitch(&GotoHomeSP);
965  CoilPowerSP.s = IPS_ALERT;
966  IDSetSwitch(&GotoHomeSP, nullptr);
967  return false;
968  }
969 
970  GotoHomeSP.s = IPS_OK;
971  IDSetSwitch(&GotoHomeSP, nullptr);
972  return true;
973  }
974 
975  // Coil Power Mode
976  if (strcmp(CoilPowerSP.name, name) == 0)
977  {
978  int current_mode = IUFindOnSwitchIndex(&CoilPowerSP);
979 
980  IUUpdateSwitch(&CoilPowerSP, states, names, n);
981 
982  int target_mode = IUFindOnSwitchIndex(&CoilPowerSP);
983 
984  if (current_mode == target_mode)
985  {
986  CoilPowerSP.s = IPS_OK;
987  IDSetSwitch(&CoilPowerSP, nullptr);
988  }
989 
990  bool rc = setCoilPowerState(static_cast<CoilPower>(target_mode));
991  if (!rc)
992  {
993  IUResetSwitch(&CoilPowerSP);
994  CoilPowerS[current_mode].s = ISS_ON;
995  CoilPowerSP.s = IPS_ALERT;
996  IDSetSwitch(&CoilPowerSP, nullptr);
997  return false;
998  }
999 
1000  CoilPowerSP.s = IPS_OK;
1001  IDSetSwitch(&CoilPowerSP, nullptr);
1002  return true;
1003  }
1004 
1005  // Display Control
1006  if (strcmp(DisplaySP.name, name) == 0)
1007  {
1008  int current_mode = IUFindOnSwitchIndex(&DisplaySP);
1009 
1010  IUUpdateSwitch(&DisplaySP, states, names, n);
1011 
1012  int target_mode = IUFindOnSwitchIndex(&DisplaySP);
1013 
1014  if (current_mode == target_mode)
1015  {
1016  DisplaySP.s = IPS_OK;
1017  IDSetSwitch(&DisplaySP, nullptr);
1018  }
1019 
1020  bool rc = setDisplayVisible(static_cast<DisplayMode>(target_mode));
1021  if (!rc)
1022  {
1023  IUResetSwitch(&DisplaySP);
1024  DisplayS[current_mode].s = ISS_ON;
1025  DisplaySP.s = IPS_ALERT;
1026  IDSetSwitch(&DisplaySP, nullptr);
1027  return false;
1028  }
1029 
1030  DisplaySP.s = IPS_OK;
1031  IDSetSwitch(&DisplaySP, nullptr);
1032  return true;
1033  }
1034 
1035  // Backlash In Enable
1036  if (strcmp(BacklashInSP.name, name) == 0)
1037  {
1038  int current_mode = IUFindOnSwitchIndex(&BacklashInSP);
1039 
1040  IUUpdateSwitch(&BacklashInSP, states, names, n);
1041 
1042  int target_mode = IUFindOnSwitchIndex(&BacklashInSP);
1043 
1044  if (current_mode == target_mode)
1045  {
1046  BacklashInSP.s = IPS_OK;
1047  IDSetSwitch(&BacklashInSP, nullptr);
1048  }
1049 
1050  bool rc = setBacklashInEnabled(target_mode == INDI_ENABLED);
1051  if (!rc)
1052  {
1053  IUResetSwitch(&BacklashInSP);
1054  BacklashInS[current_mode].s = ISS_ON;
1055  BacklashInSP.s = IPS_ALERT;
1056  IDSetSwitch(&BacklashInSP, nullptr);
1057  return false;
1058  }
1059 
1060  BacklashInSP.s = IPS_OK;
1061  IDSetSwitch(&BacklashInSP, nullptr);
1062  return true;
1063  }
1064 
1065  // Backlash Out Enable
1066  if (strcmp(BacklashOutSP.name, name) == 0)
1067  {
1068  int current_mode = IUFindOnSwitchIndex(&BacklashOutSP);
1069 
1070  IUUpdateSwitch(&BacklashOutSP, states, names, n);
1071 
1072  int target_mode = IUFindOnSwitchIndex(&BacklashOutSP);
1073 
1074  if (current_mode == target_mode)
1075  {
1076  BacklashOutSP.s = IPS_OK;
1077  IDSetSwitch(&BacklashOutSP, nullptr);
1078  }
1079 
1080  bool rc = setBacklashOutEnabled(target_mode == INDI_ENABLED);
1081  if (!rc)
1082  {
1083  IUResetSwitch(&BacklashOutSP);
1084  BacklashOutS[current_mode].s = ISS_ON;
1085  BacklashOutSP.s = IPS_ALERT;
1086  IDSetSwitch(&BacklashOutSP, nullptr);
1087  return false;
1088  }
1089 
1090  BacklashOutSP.s = IPS_OK;
1091  IDSetSwitch(&BacklashOutSP, nullptr);
1092  return true;
1093  }
1094 
1095  // Temperature Compensation Mode
1096  if (strcmp(TemperatureCompensateSP.name, name) == 0)
1097  {
1098  int last_index = IUFindOnSwitchIndex(&TemperatureCompensateSP);
1099  IUUpdateSwitch(&TemperatureCompensateSP, states, names, n);
1100 
1101  bool rc = setTemperatureCompensation((TemperatureCompensateS[0].s == ISS_ON));
1102 
1103  if (!rc)
1104  {
1105  TemperatureCompensateSP.s = IPS_ALERT;
1106  IUResetSwitch(&TemperatureCompensateSP);
1107  TemperatureCompensateS[last_index].s = ISS_ON;
1108  IDSetSwitch(&TemperatureCompensateSP, nullptr);
1109  return false;
1110  }
1111 
1112  TemperatureCompensateSP.s = IPS_OK;
1113  IDSetSwitch(&TemperatureCompensateSP, nullptr);
1114  return true;
1115  }
1116  }
1117 
1118  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
1119 }
1120 
1121 bool MyFocuserPro2::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
1122 {
1123  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
1124  {
1125  // Temperature Settings
1126  if (strcmp(name, TemperatureSettingNP.name) == 0)
1127  {
1128  IUUpdateNumber(&TemperatureSettingNP, values, names, n);
1129  if (!setTemperatureCoefficient(TemperatureSettingN[0].value))
1130  {
1131  TemperatureSettingNP.s = IPS_ALERT;
1132  IDSetNumber(&TemperatureSettingNP, nullptr);
1133  return false;
1134  }
1135 
1136  TemperatureSettingNP.s = IPS_OK;
1137  IDSetNumber(&TemperatureSettingNP, nullptr);
1138  return true;
1139  }
1140 
1141  // Backlash In
1142  if (strcmp(name, BacklashInStepsNP.name) == 0)
1143  {
1144  IUUpdateNumber(&BacklashInStepsNP, values, names, n);
1145  if (!setBacklashInSteps(BacklashInStepsN[0].value))
1146  {
1147  BacklashInStepsNP.s = IPS_ALERT;
1148  IDSetNumber(&BacklashInStepsNP, nullptr);
1149  return false;
1150  }
1151 
1152  BacklashInStepsNP.s = IPS_OK;
1153  IDSetNumber(&BacklashInStepsNP, nullptr);
1154  return true;
1155  }
1156 
1157  // Backlash Out
1158  if (strcmp(name, BacklashOutStepsNP.name) == 0)
1159  {
1160  IUUpdateNumber(&BacklashOutStepsNP, values, names, n);
1161  if (!setBacklashOutSteps(BacklashOutStepsN[0].value))
1162  {
1163  BacklashOutStepsNP.s = IPS_ALERT;
1164  IDSetNumber(&BacklashOutStepsNP, nullptr);
1165  return false;
1166  }
1167 
1168  BacklashOutStepsNP.s = IPS_OK;
1169  IDSetNumber(&BacklashOutStepsNP, nullptr);
1170  return true;
1171  }
1172 
1173  }
1174 
1175  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
1176 }
1177 
1178 void MyFocuserPro2::getStartupValues()
1179 {
1180  readMaxPos();
1181  readPosition();
1182  readTemperature();
1183  readTemperatureCoefficient();
1184  readSpeed();
1185  readTempCompensateEnable();
1186  readStepMode();
1187  readCoilPowerState();
1188  readDisplayVisible();
1189  readReverseDirection();
1190  readBacklashInEnabled();
1191  readBacklashOutEnabled();
1192  readBacklashInSteps();
1193  readBacklashOutSteps();
1194 }
1195 
1197 {
1198  return setSpeed(speed);
1199 }
1200 
1201 
1203 {
1204  char cmd[ML_RES] = {0};
1205 
1206  snprintf(cmd, ML_RES, ":07%06d#", maxPos);
1207 
1208  if(sendCommand(cmd))
1209  {
1210  Focuser::SyncPresets(maxPos);
1211  return true;
1212  }
1213  return false;
1214 }
1215 
1216 IPState MyFocuserPro2::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
1217 {
1218  if (speed != static_cast<int>(FocusSpeedN[0].value))
1219  {
1220  if (!setSpeed(speed))
1221  {
1222  return IPS_ALERT;
1223  }
1224  }
1225 
1226  // either go all the way in or all the way out
1227  // then use timer to stop
1228  if (dir == FOCUS_INWARD)
1229  {
1230  MoveFocuser(0);
1231  }
1232  else
1233  {
1234  MoveFocuser(FocusMaxPosN[0].value);
1235  }
1236 
1237  IEAddTimer(duration, &MyFocuserPro2::timedMoveHelper, this);
1238  return IPS_BUSY;
1239 }
1240 
1242 {
1243  static_cast<MyFocuserPro2 *>(context)->timedMoveCallback();
1244 }
1245 
1246 void MyFocuserPro2::timedMoveCallback()
1247 {
1248  AbortFocuser();
1252  FocusTimerN[0].value = 0;
1253  IDSetNumber(&FocusAbsPosNP, nullptr);
1254  IDSetNumber(&FocusRelPosNP, nullptr);
1255  IDSetNumber(&FocusTimerNP, nullptr);
1256 }
1257 
1259 {
1260  targetPos = targetTicks;
1261 
1262  if (!MoveFocuser(targetPos))
1263  {
1264  return IPS_ALERT;
1265  }
1266  return IPS_BUSY;
1267 }
1268 
1270 {
1271  int32_t newPosition = 0;
1272 
1273  if (dir == FOCUS_INWARD)
1274  {
1275  newPosition = FocusAbsPosN[0].value - ticks;
1276  }
1277  else
1278  {
1279  newPosition = FocusAbsPosN[0].value + ticks;
1280  }
1281 
1282  // Clamp
1283  newPosition = std::max(0, std::min(static_cast<int32_t>(FocusAbsPosN[0].max), newPosition));
1284  if (!MoveFocuser(newPosition))
1285  {
1286  return IPS_ALERT;
1287  }
1288 
1289  FocusRelPosN[0].value = ticks;
1291 
1292  return IPS_BUSY;
1293 }
1294 
1295 // this is occuring every 500ms
1297 {
1298  if (!isConnected())
1299  {
1301  return;
1302  }
1303 
1304  // update position every 1s
1305  if (Position_Counter++ == GET_POSITION_FREQ)
1306  {
1307  //LOG_INFO("Focuser refresh position.");
1308  Position_Counter = 0;
1309  bool rc = readPosition();
1310  if (rc)
1311  {
1312  if (fabs(lastPos - FocusAbsPosN[0].value) > 5)
1313  {
1314  IDSetNumber(&FocusAbsPosNP, nullptr);
1315  lastPos = FocusAbsPosN[0].value;
1316  }
1317  }
1319  {
1320  if (!isMoving())
1321  {
1324  IDSetNumber(&FocusAbsPosNP, nullptr);
1325  IDSetNumber(&FocusRelPosNP, nullptr);
1326  lastPos = FocusAbsPosN[0].value;
1327  LOG_INFO("Focuser reached requested position.");
1328  }
1329  }
1330  }
1331 
1333  {
1334  if (!isMoving())
1335  {
1338  IDSetNumber(&FocusAbsPosNP, nullptr);
1339  IDSetNumber(&FocusRelPosNP, nullptr);
1340  lastPos = FocusAbsPosN[0].value;
1341  LOG_INFO("Focuser reached requested position.");
1342  }
1343  }
1344 
1345  // update temperature every 5s
1346  if (Temperature_Counter++ == GET_TEMPERATURE_FREQ)
1347  {
1348  //LOG_INFO("Focuser refresh Temperature.");
1349  Temperature_Counter = 0;
1350  bool rc = readTemperature();
1351  if (rc)
1352  {
1353  if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
1354  {
1355  IDSetNumber(&TemperatureNP, nullptr);
1356  lastTemperature = TemperatureN[0].value;
1357  }
1358  }
1359  }
1361 }
1362 
1364 {
1365  return sendCommand(":27#");
1366 }
1367 
1369 {
1370  Focuser::saveConfigItems(fp);
1371 
1372  IUSaveConfigNumber(fp, &TemperatureSettingNP);
1373  IUSaveConfigSwitch(fp, &TemperatureCompensateSP);
1374  IUSaveConfigSwitch(fp, &BacklashInSP);
1375  IUSaveConfigNumber(fp, &BacklashInStepsNP);
1376  IUSaveConfigSwitch(fp, &BacklashOutSP);
1377  IUSaveConfigNumber(fp, &BacklashOutStepsNP);
1378  IUSaveConfigSwitch(fp, &StepModeSP);
1379  IUSaveConfigSwitch(fp, &DisplaySP);
1380 
1381  return true;
1382 }
1383 
1384 // sleep for a number of milliseconds
1385 int MyFocuserPro2::msleep( long duration)
1386 {
1387  struct timespec ts;
1388  int res;
1389 
1390  if (duration < 0)
1391  {
1392  errno = EINVAL;
1393  return -1;
1394  }
1395 
1396  ts.tv_sec = duration / 1000;
1397  ts.tv_nsec = (duration % 1000) * 1000000;
1398 
1399  do
1400  {
1401  res = nanosleep(&ts, &ts);
1402  }
1403  while (res && errno == EINTR);
1404 
1405  return res;
1406 }
1407 
1408 void MyFocuserPro2::clearbufferonerror()
1409 {
1410  bool rc;
1411  char res[ML_RES] = {0};
1412  int nbytes_read = 0;
1413 
1414  // if the driver and controller get out of sync, this is an attempt to recover from that situation
1415  // attempt to clear the receive buffer if the controller response arrived after a serial timeout
1416  pthread_mutex_lock(&cmdlock);
1417  msleep(MYFOCUSERPRO2_RECOVER_DELAY);
1419  {
1420  rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read);
1421  }
1422  else
1423  {
1424  // assume TCP/IP Connection
1425  rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read);
1426  }
1427  pthread_mutex_unlock(&cmdlock);
1428  if( rc != TTY_OK)
1429  {
1430  //LOGF_ERROR("No data read from controller");
1431  }
1432  else
1433  {
1434  LOGF_ERROR("Data read from controller: %s.", res);
1435  }
1436 }
1437 
1438 bool MyFocuserPro2::sendCommand(const char * cmd, char * res)
1439 {
1440  int nbytes_written = 0, nbytes_read = 0, rc = -1;
1441 
1442  tcflush(PortFD, TCIOFLUSH);
1443 
1444  LOGF_DEBUG("CMD <%s>", cmd);
1445 
1446  pthread_mutex_lock(&cmdlock);
1447  if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
1448  {
1449  char errstr[MAXRBUF] = {0};
1450  tty_error_msg(rc, errstr, MAXRBUF);
1451  LOGF_ERROR("Connection write error: %s.", errstr);
1452  pthread_mutex_unlock(&cmdlock);
1453  return false;
1454  }
1455 
1456  if (res == nullptr)
1457  {
1458  tcdrain(PortFD);
1459  pthread_mutex_unlock(&cmdlock);
1460  return true;
1461  }
1462  //pthread_mutex_unlock(&cmdlock);
1463 
1464  // sleep for 20ms to give time for controller to process command before attempting to read reply
1465  msleep(MYFOCUSERPRO2_SMALL_DELAY);
1466 
1467  //pthread_mutex_lock(&cmdlock);
1468  // replace ML_TIMEOUT, needs to be dependant on connection type
1470  {
1471  rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_SERIAL_TIMEOUT, &nbytes_read);
1472  }
1473  else
1474  {
1475  // assume TCP/IP Connection
1476  rc = tty_nread_section(PortFD, res, ML_RES, ML_DEL, MYFOCUSERPRO2_TCPIP_TIMEOUT, &nbytes_read);
1477  }
1478 
1479  if (rc != TTY_OK)
1480  {
1481  char errstr[MAXRBUF] = {0};
1482  tty_error_msg(rc, errstr, MAXRBUF);
1483  LOGF_ERROR("Connection read error: %s.", errstr);
1484  pthread_mutex_unlock(&cmdlock);
1485  return false;
1486  }
1487 
1488  LOGF_DEBUG("RES <%s>", res);
1489 
1490  tcflush(PortFD, TCIOFLUSH);
1491  pthread_mutex_unlock(&cmdlock);
1492  return true;
1493 }
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
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.
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
INumberVectorProperty FocusTimerNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
Connection::TCP * tcpConnection
Definition: indifocuser.h:117
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void setSupportedConnections(const uint8_t &value)
setConnection Set Focuser connection mode. Child class should call this in the constructor before Foc...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
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
Process the client newNumber command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
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
Initilize properties initial state and value. The child class must implement this function.
@ ONEHUNDREDTWENTYEIGHT_STEP
Definition: myfocuserpro2.h:56
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:582
double max(void)
int errno
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:666
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
#define CDRIVER_VERSION_MAJOR
Definition: mydcp4esp32.h:37
#define CDRIVER_VERSION_MINOR
Definition: mydcp4esp32.h:38
#define STEPMODE_THIRTYSECOND
Definition: myfocuserpro2.h:39
#define STEPMODE_ONEHUNDREDTWENTYEIGHT
Definition: myfocuserpro2.h:41
#define STEPMODE_QUARTER
Definition: myfocuserpro2.h:36
#define STEPMODE_SIXTEENTH
Definition: myfocuserpro2.h:38
#define STEPMODE_FULL
Definition: myfocuserpro2.h:34
#define STEPMODE_SIXTYFOUR
Definition: myfocuserpro2.h:40
#define STEPMODE_HALF
Definition: myfocuserpro2.h:35
#define STEPMODE_TWOHUNDREDFIFTYSIX
Definition: myfocuserpro2.h:42
#define STEPMODE_EIGHTH
Definition: myfocuserpro2.h:37
__le16 type
Definition: pwc-ioctl.h:0
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371