Instrument Neutral Distributed Interface INDI  2.0.2
focuslynxbase.cpp
Go to the documentation of this file.
1 /*
2  Focus Lynx INDI driver
3  Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
20 #include "focuslynxbase.h"
21 
22 /************************************************************************************
23  *
24 * ***********************************************************************************/
25 FocusLynxBase::FocusLynxBase(const char *target)
26 {
27  INDI_UNUSED(target);
28 }
29 
30 /************************************************************************************
31  *
32 * ***********************************************************************************/
34 {
36 
37  lynxModels["Optec TCF-Lynx 2"] = "OA";
38  lynxModels["Optec TCF-Lynx 3"] = "OB";
39 
40  // "OC" is now reserved, it is hard coded into focusers that use it
41  // Allthough it can be selected it should not be
42  // lynxModels["Optec TCF-Lynx 2 with Extended Travel"] = "OC";
43  lynxModels["Optec Fast Focus Secondary Focuser"] = "OD";
44 
45  // "OE" and "OF" are reserved, no models that are not "OA" or "OB" have been deployed
46  // lynxModels["Optec TCF-S Classic converted"] = "OE";
47  // lynxModels["Optec TCF-S3 Classic converted"] = "OF";
48 
49  // "OG" Gemini is reserved. It is used to identify the Optec Gemini
50  // lynxModels["Optec Gemini (reserved for future use)"] = "OG";
51 
52  lynxModels["Optec Leo"] = "OI";
53  lynxModels["Optec Leo High-Torque"] = "OJ";
54  lynxModels["Optec Sagitta"] = "OK";
55  lynxModels["Optec Sagitta 2"] = "OL";
56 
57  // These are generic for all Optec QuickSync and FeatherTouch HSM models
58  lynxModels["QuickSync / HSM Hi-Torque"] = "FA";
59  lynxModels["QuickSync / HSM Hi-Speed"] = "FB";
60 
61  // "FC" is reserved, it has not been deployed and is covered by "FA" and "FB"
62  // lynxModels["FocusLynx QuickSync SV (reserved for future use)"] = "FC";
63 
64  // These are generic for all Optec DirectSync and FeatherTouch PDMS models
65  lynxModels["DirectSync / PDMS Hi-Torque"] = "FD";
66  lynxModels["DirectSync / PDMS Hi-Speed"] = "FF";
67 
68  // JM 2019-09-27: This was added after the discussion here
69  // https://www.indilib.org/forum/focusers-filter-wheels/5739-starlight-instruments-focuser-boss-ii-hsm20.html
70  // DVN 2021-11-15: Covered by the generic Device Type FA and FB.
71  // Continued: duplicating device types can result in the wrong type being displayed in the selection box
72  // lynxModels["FeatureTouch HSM Hi-Torque"] = "FA";
73  // lynxModels["FeatureTouch HSM Hi-Speed"] = "FB";
74 
75  // FE is deprecated, future firmwares will automatically switch to generic device type FD
76  lynxModels["FeatherTouch Motor PDMS"] = "FE";
77 
78  lynxModels["FeatherTouch Microtouch MSM Hi-Speed"] = "SO";
79  lynxModels["FeatherTouch Microtouch MSM Hi-Torque"] = "SP";
80  lynxModels["Starlight Instruments - FTM with MicroTouch"] = "SQ";
81 
82  //TA is deprecated, future firmwares will automatically switch to generic device type FA
83  lynxModels["Televue Focuser"] = "TA";
84 
85  lynxModels["Unipolar motor (Robo-Focus)"] = "RA";
86 
87  ModelS = nullptr;
88 
89  focusMoveRequest = 0;
90  simPosition = 0;
91 
92  // Can move in Absolute & Relative motions, can AbortFocuser motion, can sync, and has variable speed.
99 
100  canHome = false;
101  isHoming = false;
102 
103  simStatus[STATUS_MOVING] = ISS_OFF;
104  simStatus[STATUS_HOMING] = ISS_OFF;
105  simStatus[STATUS_HOMED] = ISS_OFF;
106  simStatus[STATUS_FFDETECT] = ISS_OFF;
107  simStatus[STATUS_TMPPROBE] = ISS_ON;
108  simStatus[STATUS_REMOTEIO] = ISS_ON;
109  simStatus[STATUS_HNDCTRL] = ISS_ON;
110  simStatus[STATUS_REVERSE] = ISS_OFF;
111 }
112 
113 /************************************************************************************
114  *
115 * ***********************************************************************************/
117 {
119 
120  // Focuser temperature
121  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
122  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
124 
125  // Enable/Disable temperature compensation
126  IUFillSwitch(&TemperatureCompensateS[INDI_ENABLED], "INDI_ENABLED", "Enabled", ISS_OFF);
127  IUFillSwitch(&TemperatureCompensateS[INDI_DISABLED], "INDI_DISABLED", "Disabled", ISS_ON);
128  IUFillSwitchVector(&TemperatureCompensateSP, TemperatureCompensateS, 2, getDeviceName(), "T. COMPENSATION",
129  "T. Compensation",
131 
132  // Enable/Disable temperature compensation on start
133  IUFillSwitch(&TemperatureCompensateOnStartS[0], "Enable", "Enable", ISS_OFF);
134  IUFillSwitch(&TemperatureCompensateOnStartS[1], "Disable", "Disable", ISS_ON);
135  IUFillSwitchVector(&TemperatureCompensateOnStartSP, TemperatureCompensateOnStartS, 2, getDeviceName(),
136  "T. COMPENSATION @START", "T. Compensation @Start", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
137 
138  // Enable/Disable temperature Mode
139  IUFillSwitch(&TemperatureCompensateModeS[0], "A", "A", ISS_OFF);
140  IUFillSwitch(&TemperatureCompensateModeS[1], "B", "B", ISS_OFF);
141  IUFillSwitch(&TemperatureCompensateModeS[2], "C", "C", ISS_OFF);
142  IUFillSwitch(&TemperatureCompensateModeS[3], "D", "D", ISS_OFF);
143  IUFillSwitch(&TemperatureCompensateModeS[4], "E", "E", ISS_OFF);
144  IUFillSwitchVector(&TemperatureCompensateModeSP, TemperatureCompensateModeS, 5, getDeviceName(), "COMPENSATE MODE",
145  "Compensate Mode", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
146 
147  IUFillNumber(&TemperatureParamN[0], "T. Coefficient", "", "%.f", -9999, 9999, 100., 0.);
148  IUFillNumber(&TemperatureParamN[1], "T. Intercept", "", "%.f", -32766, 32766, 100., 0.);
149  IUFillNumberVector(&TemperatureParamNP, TemperatureParamN, 2, getDeviceName(), "T. PARAMETERS", "Mode Parameters",
151 
152  // Focuser Step Size
153  // An early command doc listed this as 10000 instead of the correct 1000. Because this is informational only (not used within the controller)
154  // fixing it should have no consequences.
155  IUFillNumber(&StepSizeN[0], "1000*microns/step", "", "%.f", 0, 65535, 0., 0);
156  IUFillNumberVector(&StepSizeNP, StepSizeN, 1, getDeviceName(), "STEP SIZE", "Step Size", FOCUS_SETTINGS_TAB, IP_RW, 0,
157  IPS_IDLE);
158 
159  // Reset to Factory setting
160  IUFillSwitch(&ResetS[0], "Factory", "Factory", ISS_OFF);
161  IUFillSwitchVector(&ResetSP, ResetS, 1, getDeviceName(), "RESET", "Reset", FOCUS_SETTINGS_TAB, IP_RW, ISR_ATMOST1, 0,
162  IPS_IDLE);
163 
164  // Go to home/center
165  IUFillSwitch(&GotoS[GOTO_CENTER], "Center", "Center", ISS_OFF);
166  IUFillSwitch(&GotoS[GOTO_HOME], "Home", "Home", ISS_OFF);
167  IUFillSwitchVector(&GotoSP, GotoS, 2, getDeviceName(), "GOTO", "Goto", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0,
168  IPS_IDLE);
169 
170  // List all supported models
171  std::map<std::string, std::string>::iterator iter;
172  int nModels = 1;
173  ModelS = static_cast<ISwitch *>(malloc(sizeof(ISwitch)));
174  // Need to be able to select no focuser to avoid troubles with Ekos
175  IUFillSwitch(ModelS, "No Focuser", "No Focuser", ISS_ON);
176  for (iter = lynxModels.begin(); iter != lynxModels.end(); ++iter)
177  {
178  ISwitch * buffer = static_cast<ISwitch *>(realloc(ModelS, (nModels + 1) * sizeof(ISwitch)));
179  if (!buffer)
180  {
181  free(ModelS);
182  return false;
183  }
184  else
185  ModelS = buffer;
186  IUFillSwitch(ModelS + nModels, (iter->first).c_str(), (iter->first).c_str(), ISS_OFF);
187 
188  nModels++;
189  }
190  IUFillSwitchVector(&ModelSP, ModelS, nModels, getDeviceName(), "MODEL", "Model", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0,
191  IPS_IDLE);
192 
193  // Status indicators
194  IUFillLight(&StatusL[STATUS_MOVING], "Is Moving", "", IPS_IDLE);
195  IUFillLight(&StatusL[STATUS_HOMING], "Is Homing", "", IPS_IDLE);
196  IUFillLight(&StatusL[STATUS_HOMED], "Is Homed", "", IPS_IDLE);
197  IUFillLight(&StatusL[STATUS_FFDETECT], "FF Detect", "", IPS_IDLE);
198  IUFillLight(&StatusL[STATUS_TMPPROBE], "Tmp Probe", "", IPS_IDLE);
199  IUFillLight(&StatusL[STATUS_REMOTEIO], "Remote IO", "", IPS_IDLE);
200  IUFillLight(&StatusL[STATUS_HNDCTRL], "Hnd Ctrl", "", IPS_IDLE);
201  IUFillLight(&StatusL[STATUS_REVERSE], "Reverse", "", IPS_IDLE);
202  IUFillLightVector(&StatusLP, StatusL, 8, getDeviceName(), "STATUS", "Status", FOCUS_STATUS_TAB, IPS_IDLE);
203 
204  // Focus name configure in the HUB
205  IUFillText(&HFocusNameT[0], "FocusName", "Focuser name", "");
206  IUFillTextVector(&HFocusNameTP, HFocusNameT, 1, getDeviceName(), "FOCUSNAME", "Focuser", FOCUS_SETTINGS_TAB, IP_RW, 0,
207  IPS_IDLE);
208 
209  // Led intensity value
210  IUFillNumber(&LedN[0], "Intensity", "", "%.f", 0, 100, 5., 0.);
212  //simPosition = FocusAbsPosN[0].value;
213 
214  addAuxControls();
215 
216  return true;
217 }
218 
219 /************************************************************************************
220  *
221 * ***********************************************************************************/
222 void FocusLynxBase::ISGetProperties(const char *dev)
223 {
224  if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
225  return;
226 
228 
230  if (isSimulation())
231  loadConfig(true, "Model");
232 }
233 
234 /************************************************************************************
235  *
236 * ***********************************************************************************/
238 {
239  // For homing focusers the vector is set to RO, as we get value from the HUB
240 
241  if(canHome)
242  {
244  }
245  else
246  {
248  }
249 
251 
252  if (isConnected())
253  {
254  defineProperty(&HFocusNameTP);
255 
256  defineProperty(&TemperatureNP);
257  defineProperty(&TemperatureCompensateModeSP);
258  defineProperty(&TemperatureParamNP);
259  defineProperty(&TemperatureCompensateSP);
260  defineProperty(&TemperatureCompensateOnStartSP);
261 
262  // defineProperty(&FocusBacklashSP);
263  // defineProperty(&FocusBacklashNP);
264 
265  //defineProperty(&MaxTravelNP);
266 
267  defineProperty(&StepSizeNP);
268 
269  defineProperty(&ResetSP);
270  //defineProperty(&ReverseSP);
271  defineProperty(&StatusLP);
272 
273  if (getFocusConfig() && getFocusTemp())
274  LOG_INFO("FocusLynx parameters updated, focuser ready for use.");
275  else
276  {
277  LOG_ERROR("Failed to retrieve focuser configuration settings...");
278  return false;
279  }
280  }
281  else
282  {
283  deleteProperty(TemperatureNP.name);
284  deleteProperty(TemperatureCompensateModeSP.name);
285  deleteProperty(TemperatureCompensateSP.name);
286  deleteProperty(TemperatureParamNP.name);
287  deleteProperty(TemperatureCompensateOnStartSP.name);
288 
289  // deleteProperty(FocusBacklashSP.name);
290  // deleteProperty(FocusBacklashNP.name);
291 
292  //deleteProperty(MaxTravelNP.name);
293  deleteProperty(StepSizeNP.name);
294 
295  deleteProperty(ResetSP.name);
296  deleteProperty(GotoSP.name);
297  //deleteProperty(ReverseSP.name);
298 
299  deleteProperty(StatusLP.name);
300  deleteProperty(HFocusNameTP.name);
301  }
302 
303  return true;
304 }
305 
306 /************************************************************************************
307  *
308 * ***********************************************************************************/
310 {
311  if (ack())
312  {
313  LOG_INFO("FocusLynx is online. Getting focus parameters...");
314  return true;
315  }
316 
317  LOG_INFO("Error retrieving data from FocusLynx, please ensure FocusLynxBase controller is "
318  "powered and the port is correct.");
319  return false;
320 }
321 
322 /************************************************************************************
323  *
324 * ***********************************************************************************/
326 {
327  // Has to be overide by child instance
328  return "FocusLynxBase";
329 }
330 
331 /************************************************************************************
332  *
333 * ***********************************************************************************/
334 bool FocusLynxBase::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
335 {
336  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
337  {
338  // Models
339  if (strcmp(ModelSP.name, name) == 0)
340  {
341  IUUpdateSwitch(&ModelSP, states, names, n);
342  ModelSP.s = IPS_OK;
343  IDSetSwitch(&ModelSP, nullptr);
344  if (isConnected())
345  {
347  LOG_INFO("Focuser model set. Please disconnect and reconnect now...");
348  }
349  else
350  LOG_INFO("Focuser model set. Please connect now...");
351 
352  //Read the config for this new model form the HUB
353  getFocusConfig();
354 
355  return true;
356  }
357 
358  // Temperature Compensation
359  if (strcmp(TemperatureCompensateSP.name, name) == 0)
360  {
361  int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateSP);
362  IUUpdateSwitch(&TemperatureCompensateSP, states, names, n);
363  if (setTemperatureCompensation(TemperatureCompensateS[0].s == ISS_ON))
364  {
365  TemperatureCompensateSP.s = IPS_OK;
366  }
367  else
368  {
369  IUResetSwitch(&TemperatureCompensateSP);
370  TemperatureCompensateSP.s = IPS_ALERT;
371  TemperatureCompensateS[prevIndex].s = ISS_ON;
372  }
373 
374  IDSetSwitch(&TemperatureCompensateSP, nullptr);
375  return true;
376  }
377 
378  // Temperature Compensation on Start
379  if (!strcmp(TemperatureCompensateOnStartSP.name, name))
380  {
381  int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateOnStartSP);
382  IUUpdateSwitch(&TemperatureCompensateOnStartSP, states, names, n);
383  if (setTemperatureCompensationOnStart(TemperatureCompensateOnStartS[0].s == ISS_ON))
384  {
385  TemperatureCompensateOnStartSP.s = IPS_OK;
386  }
387  else
388  {
389  IUResetSwitch(&TemperatureCompensateOnStartSP);
390  TemperatureCompensateOnStartSP.s = IPS_ALERT;
391  TemperatureCompensateOnStartS[prevIndex].s = ISS_ON;
392  }
393 
394  IDSetSwitch(&TemperatureCompensateOnStartSP, nullptr);
395  return true;
396  }
397 
398  // Temperature Compensation Mode
399  if (!strcmp(TemperatureCompensateModeSP.name, name))
400  {
401  int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateModeSP);
402  IUUpdateSwitch(&TemperatureCompensateModeSP, states, names, n);
403  char mode = IUFindOnSwitchIndex(&TemperatureCompensateModeSP) + 'A';
404  if (setTemperatureCompensationMode(mode))
405  {
406  TemperatureCompensateModeSP.s = IPS_OK;
407  }
408  else
409  {
410  IUResetSwitch(&TemperatureCompensateModeSP);
411  TemperatureCompensateModeSP.s = IPS_ALERT;
412  TemperatureCompensateModeS[prevIndex].s = ISS_ON;
413  }
414 
415  IDSetSwitch(&TemperatureCompensateModeSP, nullptr);
416  return true;
417  }
418 
419  // Backlash enable/disable
420  // if (!strcmp(FocusBacklashSP.name, name))
421  // {
422  // int prevIndex = IUFindOnSwitchIndex(&FocusBacklashSP);
423  // IUUpdateSwitch(&FocusBacklashSP, states, names, n);
424  // if (setBacklashCompensation(FocusBacklashS[INDI_ENABLED].s == ISS_ON))
425  // {
426  // FocusBacklashSP.s = IPS_OK;
427  // }
428  // else
429  // {
430  // IUResetSwitch(&FocusBacklashSP);
431  // FocusBacklashSP.s = IPS_ALERT;
432  // FocusBacklashS[prevIndex].s = ISS_ON;
433  // }
434 
435  // IDSetSwitch(&FocusBacklashSP, nullptr);
436  // return true;
437  // }
438 
439  // Reset to Factory setting
440  if (strcmp(ResetSP.name, name) == 0)
441  {
442  IUResetSwitch(&ResetSP);
443  if (resetFactory())
444  ResetSP.s = IPS_OK;
445  else
446  ResetSP.s = IPS_ALERT;
447 
448  IDSetSwitch(&ResetSP, nullptr);
449  return true;
450  }
451 
452  // Go to home/center
453  if (!strcmp(GotoSP.name, name))
454  {
455  IUUpdateSwitch(&GotoSP, states, names, n);
456 
457  if (GotoS[GOTO_HOME].s == ISS_ON)
458  {
459  if (home())
460  GotoSP.s = IPS_BUSY;
461  else
462  GotoSP.s = IPS_ALERT;
463  }
464  else
465  {
466  if (center())
467  GotoSP.s = IPS_BUSY;
468  else
469  GotoSP.s = IPS_ALERT;
470  }
471 
472  IDSetSwitch(&GotoSP, nullptr);
473  return true;
474  }
475 
476  // Reverse Direction
477  // if (!strcmp(ReverseSP.name, name))
478  // {
479  // IUUpdateSwitch(&ReverseSP, states, names, n);
480 
481  // if (reverse(ReverseS[0].s == ISS_ON))
482  // ReverseSP.s = IPS_OK;
483  // else
484  // ReverseSP.s = IPS_ALERT;
485 
486  // IDSetSwitch(&ReverseSP, nullptr);
487  // return true;
488  // }
489 
490  }
491  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
492 }
493 
494 /************************************************************************************
495  *
496 * ***********************************************************************************/
497 bool FocusLynxBase::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
498 {
499  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
500  {
501  // Set device nickname to the HUB itself
502  if (!strcmp(name, HFocusNameTP.name))
503  {
504  IUUpdateText(&HFocusNameTP, texts, names, n);
505  if (setDeviceNickname(HFocusNameT[0].text))
506  HFocusNameTP.s = IPS_OK;
507  else
508  HFocusNameTP.s = IPS_ALERT;
509  IDSetText(&HFocusNameTP, nullptr);
510  return true;
511  }
512  }
513  return INDI::Focuser::ISNewText(dev, name, texts, names, n);
514 }
515 
516 /************************************************************************************
517  *
518 * ***********************************************************************************/
519 bool FocusLynxBase::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
520 {
521  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
522  {
523  // Temperature Coefficient & Inceptions
524  if (!strcmp(TemperatureParamNP.name, name))
525  {
526  IUUpdateNumber(&TemperatureParamNP, values, names, n);
527 
528  char mode = static_cast<char>(65 + IUFindOnSwitchIndex(&TemperatureCompensateModeSP));
529  if (!setTemperatureCompensationCoeff(mode, TemperatureParamN[0].value) ||
530  !setTemperatureInceptions(mode, TemperatureParamN[1].value))
531  {
532  LOG_ERROR("Failed to write temperature coefficient or intercept");
533  TemperatureParamNP.s = IPS_ALERT;
534  IDSetNumber(&TemperatureParamNP, nullptr);
535  return false;
536  }
537 
538  TemperatureParamNP.s = IPS_OK;
539  getFocusTemp();
540 
541  return true;
542  }
543 
544  // Backlash Value
545  // if (!strcmp(FocusBacklashNP.name, name))
546  // {
547  // IUUpdateNumber(&FocusBacklashNP, values, names, n);
548  // if (setFocusBacklashSteps(FocusBacklashN[0].value) == false)
549  // {
550  // LOG_ERROR("Failed to set temperature coefficients.");
551  // FocusBacklashNP.s = IPS_ALERT;
552  // IDSetNumber(&FocusBacklashNP, nullptr);
553  // return false;
554  // }
555 
556  // FocusBacklashNP.s = IPS_OK;
557  // IDSetNumber(&FocusBacklashNP, nullptr);
558  // return true;
559  // }
560 
561  // Sync
562  // if (strcmp(SyncNP.name, name) == 0)
563  // {
564  // IUUpdateNumber(&SyncNP, values, names, n);
565  // if (sync(SyncN[0].value) == false)
566  // {
567  // LOG_ERROR("Failed to set the actual value.");
568  // SyncNP.s = IPS_ALERT;
569  // IDSetNumber(&SyncNP, nullptr);
570  // return false;
571  // }
572  // else
573  // SyncNP.s = IPS_OK;
574 
575  // IDSetNumber(&SyncNP, nullptr);
576  // return true;
577  // }
578 
579  // StepSize
580  if (strcmp(StepSizeNP.name, name) == 0)
581  {
582  IUUpdateNumber(&StepSizeNP, values, names, n);
583  if (setStepSize(StepSizeN[0].value) == false)
584  {
585  LOG_ERROR("Failed to set the actual value.");
586  StepSizeNP.s = IPS_ALERT;
587  IDSetNumber(&StepSizeNP, nullptr);
588  return false;
589  }
590  else
591  StepSizeNP.s = IPS_OK;
592 
593  IDSetNumber(&StepSizeNP, nullptr);
594  return true;
595  }
596 
597  // Max Travel if relative focusers
598  // if (strcmp(MaxTravelNP.name, name) == 0)
599  // {
600  // IUUpdateNumber(&MaxTravelNP, values, names, n);
601 
602  // if (setMaxTravel(MaxTravelN[0].value) == false)
603  // MaxTravelNP.s = IPS_ALERT;
604  // else
605  // {
606  // MaxTravelNP.s = IPS_OK;
607  // FocusAbsPosN[0].max = SyncN[0].max = MaxTravelN[0].value;
608  // FocusAbsPosN[0].step = SyncN[0].step = (MaxTravelN[0].value / 50.0);
609 
610  // IUUpdateMinMax(&FocusAbsPosNP);
611  // IUUpdateMinMax(&SyncNP);
612 
613  // IDSetNumber(&MaxTravelNP, nullptr);
614 
615  // LOGF_INFO("Focuser absolute limits: min (%g) max (%g)", FocusAbsPosN[0].min,
616  // FocusAbsPosN[0].max);
617  // }
618  // return true;
619  // }
620 
621  // Set LED intensity to the HUB itself via function setLedLevel()
622  if (!strcmp(LedNP.name, name))
623  {
624  IUUpdateNumber(&LedNP, values, names, n);
625  if (setLedLevel(LedN[0].value))
626  LedNP.s = IPS_OK;
627  else
628  LedNP.s = IPS_ALERT;
629  LOGF_INFO("Focuser LED level intensity : %f", LedN[0].value);
630  IDSetNumber(&LedNP, nullptr);
631  return true;
632  }
633  }
634 
635  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
636 }
637 
638 /************************************************************************************
639  *
640 * ***********************************************************************************/
642 {
643  char cmd[LYNX_MAX] = {0};
644  int errcode = 0;
645  char errmsg[MAXRBUF];
646  char response[LYNX_MAX] = {0};
647  int nbytes_read = 0;
648  int nbytes_written = 0;
649 
650  memset(response, 0, sizeof(response));
651 
652  snprintf(cmd, LYNX_MAX, "<%sHELLO>", getFocusTarget());
653  LOGF_DEBUG("CMD (%s)", cmd);
654 
655  if (isSimulation())
656  {
657  const char *focusName = IUFindOnSwitch(&ModelSP)->label;
658  strncpy(response, focusName, LYNX_MAX);
659  nbytes_read = strlen(response) + 1;
660  }
661  else
662  {
663  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
664  {
665  tty_error_msg(errcode, errmsg, MAXRBUF);
666  LOGF_ERROR("%s", errmsg);
667  return false;
668  }
669 
670  if (!isResponseOK())
671  return false;
672 
673  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
674  {
675  tty_error_msg(errcode, errmsg, MAXRBUF);
676  LOGF_ERROR("%s", errmsg);
677  return false;
678  }
679  }
680 
681  if (nbytes_read > 0)
682  {
683  response[nbytes_read - 1] = '\0';
684  LOGF_DEBUG("RES (%s)", response);
685  LOGF_INFO("%s is detected.", response);
686 
687  return true;
688  }
689 
690  return false;
691 }
692 
693 /************************************************************************************
694  *
695 * ***********************************************************************************/
696 bool FocusLynxBase::getFocusConfig()
697 {
698  char cmd[LYNX_MAX] = {0};
699  int errcode = 0;
700  char errmsg[MAXRBUF];
701  char response[LYNX_MAX] = {0};
702  int nbytes_read = 0;
703  int nbytes_written = 0;
704  char key[16];
705 
706  memset(response, 0, sizeof(response));
707 
708  snprintf(cmd, LYNX_MAX, "<%sGETCONFIG>", getFocusTarget());
709  LOGF_DEBUG("CMD (%s)", cmd);
710 
711  if (isSimulation())
712  {
713  if (!strcmp(getFocusTarget(), "F1"))
714  strncpy(response, "CONFIG1", 16);
715  else
716  strncpy(response, "CONFIG2", 16);
717  nbytes_read = strlen(response) + 1;
718  }
719  else
720  {
721  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
722  {
723  tty_error_msg(errcode, errmsg, MAXRBUF);
724  LOGF_ERROR("%s", errmsg);
725  return false;
726  }
727 
728  if (!isResponseOK())
729  return false;
730 
731  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
732  {
733  tty_error_msg(errcode, errmsg, MAXRBUF);
734  LOGF_ERROR("%s", errmsg);
735  return false;
736  }
737  }
738 
739  if (nbytes_read > 0)
740  {
741  response[nbytes_read - 1] = '\0';
742  LOGF_DEBUG("RES (%s)", response);
743 
744  if ((strcmp(response, "CONFIG1")) && (strcmp(response, "CONFIG2")))
745  return false;
746  }
747 
748  memset(response, 0, sizeof(response));
749 
750  // Nickname
751  if (isSimulation())
752  {
753  snprintf(response, sizeof(response), "NickName=Focuser#%s\n", getFocusTarget());
754  nbytes_read = strlen(response);
755  }
756  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
757  {
758  tty_error_msg(errcode, errmsg, MAXRBUF);
759  LOGF_ERROR("%s", errmsg);
760  return false;
761  }
762  response[nbytes_read - 1] = '\0';
763  LOGF_DEBUG("RES (%s)", response);
764 
765  char nickname[16];
766  int rc = sscanf(response, "%15[^=]=%15[^\n]s", key, nickname);
767 
768  if (rc != 2)
769  return false;
770 
771  IUSaveText(&HFocusNameT[0], nickname);
772  IDSetText(&HFocusNameTP, nullptr);
773 
774  HFocusNameTP.s = IPS_OK;
775  IDSetText(&HFocusNameTP, nullptr);
776 
777  memset(response, 0, sizeof(response));
778 
779  // Get Max Position
780  if (isSimulation())
781  {
782  // Default value from non-homing focusers
783  snprintf(response, 32, "Max Pos = %06d\n", 65535);
784  nbytes_read = strlen(response);
785  }
786  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
787  {
788  tty_error_msg(errcode, errmsg, MAXRBUF);
789  LOGF_ERROR("%s", errmsg);
790  return false;
791  }
792  response[nbytes_read - 1] = '\0';
793  LOGF_DEBUG("RES (%s)", response);
794 
795  uint32_t maxPos = 0;
796  rc = sscanf(response, "%15[^=]=%d", key, &maxPos);
797  if (rc == 2)
798  {
799  FocusAbsPosN[0].min = 0;
800  FocusAbsPosN[0].max = maxPos;
801  FocusAbsPosN[0].step = maxPos / 50.0;
802 
803  FocusSyncN[0].min = 0;
804  FocusSyncN[0].max = maxPos;
805  FocusSyncN[0].step = maxPos / 50.0;
806 
807  FocusRelPosN[0].min = 0;
808  FocusRelPosN[0].max = maxPos / 2;
809  FocusRelPosN[0].step = maxPos / 100.0;
810 
814 
816  FocusMaxPosN[0].value = maxPos;
817  IDSetNumber(&FocusMaxPosNP, nullptr);
818 
819  }
820  else
821  return false;
822 
823  memset(response, 0, sizeof(response));
824 
825  // Get Device Type
826  if (isSimulation())
827  {
828  // In simulation each focuser is different, one Absolute and one relative
829  if (strcmp(getFocusTarget(), "F2"))
830  snprintf(response, 32, "Dev Type = %s\n", "OA");
831  else
832  snprintf(response, 32, "Dev Type = %s\n", "SO");
833  nbytes_read = strlen(response);
834  }
835  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
836  {
837  tty_error_msg(errcode, errmsg, MAXRBUF);
838  LOGF_ERROR("%s", errmsg);
839  return false;
840  }
841  response[nbytes_read - 1] = '\0';
842  LOGF_DEBUG("RES (%s)", response);
843 
844  // Don't process the response if isSimulation active, Value read from saved config
845  if (!isSimulation())
846  {
847  //Extract the code from the response value
848  std::string tmpString;
849  tmpString.assign(response + 11, 2);
850  int count = 0;
851 
852  //As "ZZ" is not exist in lynxModel, not need interator, 'No focuser' is known as first in ModelS
853  if(tmpString != "ZZ")
854  {
855  //Reset the Home / Center function
856  deleteProperty(GotoSP.name);
857  //All models that can home have the first character of the device type as the letter 'O'
858  canHome = tmpString[0] == 'O';
859 
860  if(canHome)
861  {
862  //Homing focusers can not sync
864  GotoSP.nsp = 2;
865  }
866  else
867  {
868  //Non-Homing focusers can sync
870  GotoSP.nsp = 1;
871  }
872 
873  //Reactivate the Home / Center Property
874  defineProperty(&GotoSP);
875 
876  // If not 'No Focuser' then do iterator
877  // iterate throught all elements in std::map<std::string, std::string> and search the index from the code.
878  std::map<std::string, std::string>::iterator it = lynxModels.begin();
879  while(it != lynxModels.end())
880  {
881  count++;
882  if (it->second == tmpString)
883  break;
884  it++;
885  }
886  }
887 
888  // as different focuser could have the same code in the HUB, we are not able to find the correct name in the list of focuser.
889  // The first one would be show as the item.
891  ModelS[count].s = ISS_ON;
892  IDSetSwitch(&ModelSP, nullptr);
893 
894  LOGF_DEBUG("Index focuser : %d", count);
895  } // end if (!isSimulation)
896 
897  // Get Status Parameters
898 
899  memset(response, 0, sizeof(response));
900 
901  // Temperature information processed on function getFocusTemp(), do nothing with related response
902 
903  // Temperature Compensation On
904  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
905  {
906  tty_error_msg(errcode, errmsg, MAXRBUF);
907  LOGF_ERROR("%s", errmsg);
908  return false;
909  }
910 
911  // Temperature Coeff A
912  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
913  {
914  tty_error_msg(errcode, errmsg, MAXRBUF);
915  LOGF_ERROR("%s", errmsg);
916  return false;
917  }
918 
919  // Temperature Coeff B
920  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
921  {
922  tty_error_msg(errcode, errmsg, MAXRBUF);
923  LOGF_ERROR("%s", errmsg);
924  return false;
925  }
926 
927  // Temperature Coeff C
928  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
929  {
930  tty_error_msg(errcode, errmsg, MAXRBUF);
931  LOGF_ERROR("%s", errmsg);
932  return false;
933  }
934 
935  // Temperature Coeff D
936  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
937  {
938  tty_error_msg(errcode, errmsg, MAXRBUF);
939  LOGF_ERROR("%s", errmsg);
940  return false;
941  }
942 
943  // Temperature Coeff E
944  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
945  {
946  tty_error_msg(errcode, errmsg, MAXRBUF);
947  LOGF_ERROR("%s", errmsg);
948  return false;
949  }
950 
951  // Temperature Compensation Mode
952  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
953  {
954  tty_error_msg(errcode, errmsg, MAXRBUF);
955  LOGF_ERROR("%s", errmsg);
956  return false;
957  }
958 
959  // Backlash Compensation
960  if (isSimulation())
961  {
962  snprintf(response, 32, "BLC En = %d\n", FocusBacklashS[INDI_ENABLED].s == ISS_ON ? 1 : 0);
963  nbytes_read = strlen(response);
964  }
965  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
966  {
967  tty_error_msg(errcode, errmsg, MAXRBUF);
968  LOGF_ERROR("%s", errmsg);
969  return false;
970  }
971  response[nbytes_read - 1] = '\0';
972  LOGF_DEBUG("RES (%s)", response);
973 
974  int BLCCompensate;
975  rc = sscanf(response, "%15[^=]=%d", key, &BLCCompensate);
976  if (rc != 2)
977  return false;
978 
980  FocusBacklashS[INDI_ENABLED].s = BLCCompensate ? ISS_ON : ISS_OFF;
981  FocusBacklashS[INDI_DISABLED].s = BLCCompensate ? ISS_OFF : ISS_ON;
983  IDSetSwitch(&FocusBacklashSP, nullptr);
984 
985  // Backlash Value
986  memset(response, 0, sizeof(response));
987  if (isSimulation())
988  {
989  snprintf(response, 32, "BLC Stps = %d\n", 50);
990  nbytes_read = strlen(response);
991  }
992  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
993  {
994  tty_error_msg(errcode, errmsg, MAXRBUF);
995  LOGF_ERROR("%s", errmsg);
996  return false;
997  }
998  response[nbytes_read - 1] = '\0';
999  LOGF_DEBUG("RES (%s)", response);
1000 
1001  int BLCValue;
1002  rc = sscanf(response, "%15[^=]=%d", key, &BLCValue);
1003  if (rc != 2)
1004  return false;
1005 
1006  FocusBacklashN[0].value = BLCValue;
1008  IDSetNumber(&FocusBacklashNP, nullptr);
1009 
1010  // Led brightnesss
1011  memset(response, 0, sizeof(response));
1012  if (isSimulation())
1013  {
1014  snprintf(response, 32, "LED Brt = %d\n", 75);
1015  nbytes_read = strlen(response);
1016  }
1017  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1018  {
1019  tty_error_msg(errcode, errmsg, MAXRBUF);
1020  LOGF_ERROR("%s", errmsg);
1021  return false;
1022  }
1023  response[nbytes_read - 1] = '\0';
1024  LOGF_DEBUG("RES (%s)", response);
1025 
1026  int LEDBrightness;
1027  rc = sscanf(response, "%15[^=]=%d", key, &LEDBrightness);
1028  if (rc != 2)
1029  return false;
1030 
1031  LedN[0].value = LEDBrightness;
1032  LedNP.s = IPS_OK;
1033  IDSetNumber(&LedNP, nullptr);
1034 
1035  // Temperature Compensation on Start
1036  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1037  {
1038  tty_error_msg(errcode, errmsg, MAXRBUF);
1039  LOGF_ERROR("%s", errmsg);
1040  return false;
1041  }
1042 
1043  // Home on start?
1044  // JM 2021.05.09: This appears to be a new addition in firmware v1.2.0 (2019).
1045  // We should ignore if END is received instead.
1046  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1047  {
1048  tty_error_msg(errcode, errmsg, MAXRBUF);
1049  LOGF_ERROR("%s", errmsg);
1050  return false;
1051  }
1052  // If END, then ignore
1053  else if (strncmp(response, "END", 3))
1054  {
1055  int homeOnStart;
1056  rc = sscanf(response, "%15[^=]=%d", key, &homeOnStart);
1057  if (rc != 2)
1058  return false;
1059 
1060  m_HomeOnStart = homeOnStart == 1;
1061  }
1062 
1063  // If last response was END, then ignore
1064  if (strncmp(response, "END", 3))
1065  {
1066  // END is reached
1067  memset(response, 0, sizeof(response));
1068  if (isSimulation())
1069  {
1070  strncpy(response, "END\n", 16);
1071  nbytes_read = strlen(response);
1072  }
1073  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1074  {
1075  tty_error_msg(errcode, errmsg, MAXRBUF);
1076  LOGF_ERROR("%s", errmsg);
1077  return false;
1078  }
1079  }
1080 
1081  if (nbytes_read > 0)
1082  {
1083  response[nbytes_read - 1] = '\0';
1084 
1085  // Display the response to be sure to have read the complet TTY Buffer.
1086  LOGF_DEBUG("RES (%s)", response);
1087 
1088  if (strcmp(response, "END"))
1089  return false;
1090  }
1091 
1092  tcflush(PortFD, TCIFLUSH);
1093 
1094  configurationComplete = true;
1095 
1096  return true;
1097 }
1098 
1099 /************************************************************************************
1100  *
1101 * ***********************************************************************************/
1102 bool FocusLynxBase::getFocusStatus()
1103 {
1104  char cmd[LYNX_MAX] = {0};
1105  int errcode = 0;
1106  char errmsg[MAXRBUF];
1107  char response[LYNX_MAX] = {0};
1108  int nbytes_read = 0;
1109  int nbytes_written = 0;
1110  char key[16];
1111 
1112  memset(response, 0, sizeof(response));
1113 
1114  snprintf(cmd, LYNX_MAX, "<%sGETSTATUS>", getFocusTarget());
1115  LOGF_DEBUG("CMD (%s)", cmd);
1116 
1117  if (isSimulation())
1118  {
1119  if (!strcmp(getFocusTarget(), "F1"))
1120  strncpy(response, "STATUS1", 16);
1121  else
1122  strncpy(response, "STATUS2", 16);
1123  nbytes_read = strlen(response) + 1;
1124  }
1125  else
1126  {
1127  //tcflush(PortFD, TCIFLUSH);
1128 
1129  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
1130  {
1131  tty_error_msg(errcode, errmsg, MAXRBUF);
1132  LOGF_ERROR("%s", errmsg);
1133  return false;
1134  }
1135 
1136  if (!isResponseOK())
1137  return false;
1138 
1139  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1140  {
1141  tty_error_msg(errcode, errmsg, MAXRBUF);
1142  LOGF_ERROR("%s", errmsg);
1143  return false;
1144  }
1145  }
1146 
1147  if (nbytes_read > 0)
1148  {
1149  response[nbytes_read - 1] = '\0';
1150  LOGF_DEBUG("RES (%s)", response);
1151 
1152  if (!((!strcmp(response, "STATUS1")) && (!strcmp(getFocusTarget(), "F1"))) && !((!strcmp(response, "STATUS2"))
1153  && (!strcmp(getFocusTarget(), "F2"))))
1154  {
1155  tcflush(PortFD, TCIFLUSH);
1156  return false;
1157  }
1158 
1159  // Get Temperature
1160  memset(response, 0, sizeof(response));
1161  if (isSimulation())
1162  {
1163  //strncpy(response, "Temp(C) = +21.7\n", 16); // #PS: for string literal, use strcpy
1164  strcpy(response, "Temp(C) = +21.7\n");
1165  nbytes_read = strlen(response);
1166  }
1167  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1168  {
1169  tty_error_msg(errcode, errmsg, MAXRBUF);
1170  LOGF_ERROR("%s", errmsg);
1171  return false;
1172  }
1173 
1174  if (nbytes_read > 0)
1175  response[nbytes_read - 1] = '\0'; // remove last character (new line)
1176 
1177  LOGF_DEBUG("RES (%s)", response);
1178 
1179  float temperature = 0;
1180  int rc = sscanf(response, "%15[^=]=%f", key, &temperature);
1181  if (rc == 2)
1182  {
1183  TemperatureN[0].value = temperature;
1184  IDSetNumber(&TemperatureNP, nullptr);
1185  }
1186  else
1187  {
1188  if (TemperatureNP.s != IPS_ALERT)
1189  {
1190  TemperatureNP.s = IPS_ALERT;
1191  IDSetNumber(&TemperatureNP, nullptr);
1192  }
1193  }
1194 
1195  // Get Current Position
1196  memset(response, 0, sizeof(response));
1197  if (isSimulation())
1198  {
1199  snprintf(response, 32, "Curr Pos = %06d\n", simPosition);
1200  nbytes_read = strlen(response);
1201  }
1202  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1203  {
1204  tty_error_msg(errcode, errmsg, MAXRBUF);
1205  LOGF_ERROR("%s", errmsg);
1206  return false;
1207  }
1208  response[nbytes_read - 1] = '\0';
1209  LOGF_DEBUG("RES (%s)", response);
1210 
1211  uint32_t currPos = 0;
1212  rc = sscanf(response, "%15[^=]=%d", key, &currPos);
1213  if (rc == 2)
1214  {
1215  FocusAbsPosN[0].value = currPos;
1216  IDSetNumber(&FocusAbsPosNP, nullptr);
1217  }
1218  else
1219  return false;
1220 
1221  // Get Target Position
1222  memset(response, 0, sizeof(response));
1223  if (isSimulation())
1224  {
1225  snprintf(response, 32, "Targ Pos = %06d\n", targetPosition);
1226  nbytes_read = strlen(response);
1227  }
1228  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1229  {
1230  tty_error_msg(errcode, errmsg, MAXRBUF);
1231  LOGF_ERROR("%s", errmsg);
1232  return false;
1233  }
1234  response[nbytes_read - 1] = '\0';
1235  LOGF_DEBUG("RES (%s)", response);
1236 
1237  // Get Status Parameters
1238 
1239  // #1 is Moving?
1240  memset(response, 0, sizeof(response));
1241  if (isSimulation())
1242  {
1243  snprintf(response, 32, "Is Moving = %d\n", (simStatus[STATUS_MOVING] == ISS_ON) ? 1 : 0);
1244  nbytes_read = strlen(response);
1245  }
1246  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1247  {
1248  tty_error_msg(errcode, errmsg, MAXRBUF);
1249  LOGF_ERROR("%s", errmsg);
1250  return false;
1251  }
1252  response[nbytes_read - 1] = '\0';
1253  LOGF_DEBUG("RES (%s)", response);
1254 
1255  int isMoving;
1256  rc = sscanf(response, "%15[^=]=%d", key, &isMoving);
1257  if (rc != 2)
1258  return false;
1259 
1260  StatusL[STATUS_MOVING].s = isMoving ? IPS_BUSY : IPS_IDLE;
1261 
1262  // #2 is Homing?
1263  memset(response, 0, sizeof(response));
1264  if (isSimulation())
1265  {
1266  snprintf(response, 32, "Is Homing = %d\n", (simStatus[STATUS_HOMING] == ISS_ON) ? 1 : 0);
1267  nbytes_read = strlen(response);
1268  }
1269  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1270  {
1271  tty_error_msg(errcode, errmsg, MAXRBUF);
1272  LOGF_ERROR("%s", errmsg);
1273  return false;
1274  }
1275  response[nbytes_read - 1] = '\0';
1276  LOGF_DEBUG("RES (%s)", response);
1277 
1278  int _isHoming;
1279  rc = sscanf(response, "%15[^=]=%d", key, &_isHoming);
1280  if (rc != 2)
1281  return false;
1282 
1283  StatusL[STATUS_HOMING].s = _isHoming ? IPS_BUSY : IPS_IDLE;
1284  // For syncing only focusers home is not applicable.
1285  if (canHome == false)
1286  StatusL[STATUS_HOMING].s = IPS_IDLE;
1287 
1288  // We set that isHoming in process, but we don't set it to false here it must be reset in TimerHit
1289  if (StatusL[STATUS_HOMING].s == IPS_BUSY)
1290  isHoming = true;
1291 
1292  // #3 is Homed?
1293  memset(response, 0, sizeof(response));
1294  if (isSimulation())
1295  {
1296  snprintf(response, 32, "Is Homed = %d\n", (simStatus[STATUS_HOMED] == ISS_ON) ? 1 : 0);
1297  nbytes_read = strlen(response);
1298  }
1299  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1300  {
1301  tty_error_msg(errcode, errmsg, MAXRBUF);
1302  LOGF_ERROR("%s", errmsg);
1303  return false;
1304  }
1305  response[nbytes_read - 1] = '\0';
1306  LOGF_DEBUG("RES (%s)", response);
1307 
1308  int isHomed;
1309  rc = sscanf(response, "%15[^=]=%d", key, &isHomed);
1310  if (rc != 2)
1311  return false;
1312 
1313  StatusL[STATUS_HOMED].s = isHomed ? IPS_OK : IPS_IDLE;
1314  // For relative focusers home is not applicable.
1315  if (canHome == false)
1316  StatusL[STATUS_HOMED].s = IPS_IDLE;
1317 
1318  // #4 FF Detected?
1319  memset(response, 0, sizeof(response));
1320  if (isSimulation())
1321  {
1322  snprintf(response, 32, "FFDetect = %d\n", (simStatus[STATUS_FFDETECT] == ISS_ON) ? 1 : 0);
1323  nbytes_read = strlen(response);
1324  }
1325  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1326  {
1327  tty_error_msg(errcode, errmsg, MAXRBUF);
1328  LOGF_ERROR("%s", errmsg);
1329  return false;
1330  }
1331  response[nbytes_read - 1] = '\0';
1332  LOGF_DEBUG("RES (%s)", response);
1333 
1334  int FFDetect;
1335  rc = sscanf(response, "%15[^=]=%d", key, &FFDetect);
1336  if (rc != 2)
1337  return false;
1338 
1339  StatusL[STATUS_FFDETECT].s = FFDetect ? IPS_OK : IPS_IDLE;
1340 
1341  // #5 Temperature probe?
1342  memset(response, 0, sizeof(response));
1343  if (isSimulation())
1344  {
1345  snprintf(response, 32, "TmpProbe = %d\n", (simStatus[STATUS_TMPPROBE] == ISS_ON) ? 1 : 0);
1346  nbytes_read = strlen(response);
1347  }
1348  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1349  {
1350  tty_error_msg(errcode, errmsg, MAXRBUF);
1351  LOGF_ERROR("%s", errmsg);
1352  return false;
1353  }
1354  response[nbytes_read - 1] = '\0';
1355  LOGF_DEBUG("RES (%s)", response);
1356 
1357  int TmpProbe;
1358  rc = sscanf(response, "%15[^=]=%d", key, &TmpProbe);
1359  if (rc != 2)
1360  return false;
1361 
1362  StatusL[STATUS_TMPPROBE].s = TmpProbe ? IPS_OK : IPS_IDLE;
1363 
1364  // #6 Remote IO?
1365  memset(response, 0, sizeof(response));
1366  if (isSimulation())
1367  {
1368  snprintf(response, 32, "RemoteIO = %d\n", (simStatus[STATUS_REMOTEIO] == ISS_ON) ? 1 : 0);
1369  nbytes_read = strlen(response);
1370  }
1371  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1372  {
1373  tty_error_msg(errcode, errmsg, MAXRBUF);
1374  LOGF_ERROR("%s", errmsg);
1375  return false;
1376  }
1377  response[nbytes_read - 1] = '\0';
1378  LOGF_DEBUG("RES (%s)", response);
1379 
1380  int RemoteIO;
1381  rc = sscanf(response, "%15[^=]=%d", key, &RemoteIO);
1382  if (rc != 2)
1383  return false;
1384 
1385  StatusL[STATUS_REMOTEIO].s = RemoteIO ? IPS_OK : IPS_IDLE;
1386 
1387  // #7 Hand controller?
1388  memset(response, 0, sizeof(response));
1389  if (isSimulation())
1390  {
1391  snprintf(response, 32, "Hnd Ctlr = %d\n", (simStatus[STATUS_HNDCTRL] == ISS_ON) ? 1 : 0);
1392  nbytes_read = strlen(response);
1393  }
1394  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1395  {
1396  tty_error_msg(errcode, errmsg, MAXRBUF);
1397  LOGF_ERROR("%s", errmsg);
1398  return false;
1399  }
1400  response[nbytes_read - 1] = '\0';
1401  LOGF_DEBUG("RES (%s)", response);
1402 
1403  int HndCtlr;
1404  rc = sscanf(response, "%15[^=]=%d", key, &HndCtlr);
1405  if (rc != 2)
1406  return false;
1407 
1408  StatusL[STATUS_HNDCTRL].s = HndCtlr ? IPS_OK : IPS_IDLE;
1409 
1410  // #8 Reverse?
1411  memset(response, 0, sizeof(response));
1412  if (isSimulation())
1413  {
1414  snprintf(response, 32, "Reverse = %d\n", (simStatus[STATUS_REVERSE] == ISS_ON) ? 1 : 0);
1415  nbytes_read = strlen(response);
1416  }
1417  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1418  {
1419  tty_error_msg(errcode, errmsg, MAXRBUF);
1420  LOGF_ERROR("%s", errmsg);
1421  return false;
1422  }
1423  response[nbytes_read - 1] = '\0';
1424  LOGF_DEBUG("RES (%s)", response);
1425 
1426  int reverse;
1427  rc = sscanf(response, "%15[^=]=%d", key, &reverse);
1428  if (rc != 2)
1429  return false;
1430 
1431  StatusL[STATUS_REVERSE].s = reverse ? IPS_OK : IPS_IDLE;
1432 
1433  // If reverse is enable and switch shows disabled, let's change that
1434  // same thing is reverse is disabled but switch is enabled
1435  if ((reverse && FocusReverseS[1].s == ISS_ON) || (!reverse && FocusReverseS[0].s == ISS_ON))
1436  {
1438  FocusReverseS[0].s = (reverse == 1) ? ISS_ON : ISS_OFF;
1439  FocusReverseS[1].s = (reverse == 0) ? ISS_ON : ISS_OFF;
1440  IDSetSwitch(&FocusReverseSP, nullptr);
1441  }
1442 
1443  StatusLP.s = IPS_OK;
1444  IDSetLight(&StatusLP, nullptr);
1445 
1446  // END is reached
1447  memset(response, 0, sizeof(response));
1448  if (isSimulation())
1449  {
1450  strncpy(response, "END\n", 16);
1451  nbytes_read = strlen(response);
1452  }
1453  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1454  {
1455  tty_error_msg(errcode, errmsg, MAXRBUF);
1456  LOGF_ERROR("%s", errmsg);
1457  return false;
1458  }
1459 
1460  if (nbytes_read > 0)
1461  {
1462  response[nbytes_read - 1] = '\0';
1463 
1464  // Display the response to be sure to have read the complet TTY Buffer.
1465  LOGF_DEBUG("RES (%s)", response);
1466  if (strcmp(response, "END"))
1467  return false;
1468  }
1469 
1470  tcflush(PortFD, TCIFLUSH);
1471 
1472  return true;
1473  }
1474  return false;
1475 }
1476 
1477 /************************************************************************************
1478  *
1479 * ***********************************************************************************/
1480 bool FocusLynxBase::getFocusTemp()
1481 {
1482  // Get value related to Temperature compensation
1483 
1484  char cmd[LYNX_MAX] = {0};
1485  int errcode = 0;
1486  char errmsg[MAXRBUF];
1487  char response[LYNX_MAX] = {0};
1488  int nbytes_read = 0;
1489  int nbytes_written = 0;
1490  char key[16];
1491 
1492  memset(response, 0, sizeof(response));
1493 
1494  snprintf(cmd, LYNX_MAX, "<%sGETTCI>", getFocusTarget());
1495  LOGF_DEBUG("CMD (%s)", cmd);
1496 
1497  if (isSimulation())
1498  {
1499  if (!strcmp(getFocusTarget(), "F1"))
1500  strncpy(response, "TEMP COMP1", 16);
1501  else
1502  strncpy(response, "TEMP COMP2", 16);
1503  nbytes_read = strlen(response) + 1;
1504  }
1505  else
1506  {
1507  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
1508  {
1509  tty_error_msg(errcode, errmsg, MAXRBUF);
1510  LOGF_ERROR("%s", errmsg);
1511  return false;
1512  }
1513 
1514  if (!isResponseOK())
1515  return false;
1516 
1517  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1518  {
1519  tty_error_msg(errcode, errmsg, MAXRBUF);
1520  LOGF_ERROR("%s", errmsg);
1521  return false;
1522  }
1523  }
1524 
1525  if (nbytes_read > 0)
1526  {
1527  response[nbytes_read - 1] = '\0';
1528  LOGF_DEBUG("RES (%s)", response);
1529 
1530  if ((strcmp(response, "TEMP COMP1")) && (strcmp(response, "TEMP COMP2")))
1531  return false;
1532 
1533  memset(response, 0, sizeof(response));
1534 
1535  // Temperature Compensation On?
1536  if (isSimulation())
1537  {
1538  snprintf(response, 32, "TComp ON = %d\n", TemperatureCompensateS[0].s == ISS_ON ? 1 : 0);
1539  nbytes_read = strlen(response);
1540  }
1541  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1542  {
1543  tty_error_msg(errcode, errmsg, MAXRBUF);
1544  LOGF_ERROR("%s", errmsg);
1545  return false;
1546  }
1547  response[nbytes_read - 1] = '\0';
1548  LOGF_DEBUG("RES (%s)", response);
1549 
1550  int TCompOn;
1551  int rc = sscanf(response, "%15[^=]=%d", key, &TCompOn);
1552  if (rc != 2)
1553  return false;
1554 
1555  IUResetSwitch(&TemperatureCompensateSP);
1556  TemperatureCompensateS[0].s = TCompOn ? ISS_ON : ISS_OFF;
1557  TemperatureCompensateS[1].s = TCompOn ? ISS_OFF : ISS_ON;
1558  TemperatureCompensateSP.s = IPS_OK;
1559  IDSetSwitch(&TemperatureCompensateSP, nullptr);
1560 
1561  memset(response, 0, sizeof(response));
1562 
1563  // Temperature Compensation Mode
1564  if (isSimulation())
1565  {
1566  snprintf(response, 32, "TC Mode = %c\n", 'C');
1567  nbytes_read = strlen(response);
1568  }
1569  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1570  {
1571  tty_error_msg(errcode, errmsg, MAXRBUF);
1572  LOGF_ERROR("%s", errmsg);
1573  return false;
1574  }
1575  response[nbytes_read - 1] = '\0';
1576  LOGF_DEBUG("RES (%s)", response);
1577 
1578  char compensateMode;
1579  rc = sscanf(response, "%15[^=]= %c", key, &compensateMode);
1580  if (rc != 2)
1581  {
1582  if (rc == 1 && key[0] == 'T')
1583  {
1584  //If the controller does not support this it could be null. Assume A mode in this case.
1585  compensateMode = 'A';
1586  }
1587  else
1588  {
1589  return false;
1590  }
1591  }
1592 
1593  IUResetSwitch(&TemperatureCompensateModeSP);
1594  int index = compensateMode - 'A';
1595  if (index >= 0 && index <= 5)
1596  {
1597  TemperatureCompensateModeS[index].s = ISS_ON;
1598  TemperatureCompensateModeSP.s = IPS_OK;
1599  }
1600  else
1601  {
1602  LOGF_ERROR("Invalid index %d for compensation mode.", index);
1603  TemperatureCompensateModeSP.s = IPS_ALERT;
1604  }
1605 
1606  IDSetSwitch(&TemperatureCompensateModeSP, nullptr);
1607 
1608 
1609  // Temperature Compensation on Start
1610  memset(response, 0, sizeof(response));
1611  if (isSimulation())
1612  {
1613  snprintf(response, 32, "TC@Start = %d\n", TemperatureCompensateOnStartS[0].s == ISS_ON ? 1 : 0);
1614  nbytes_read = strlen(response);
1615  }
1616  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1617  {
1618  tty_error_msg(errcode, errmsg, MAXRBUF);
1619  LOGF_ERROR("%s", errmsg);
1620  return false;
1621  }
1622  response[nbytes_read - 1] = '\0';
1623  LOGF_DEBUG("RES (%s)", response);
1624 
1625  int TCOnStart;
1626  rc = sscanf(response, "%15[^=]=%d", key, &TCOnStart);
1627  if (rc != 2)
1628  return false;
1629 
1630  IUResetSwitch(&TemperatureCompensateOnStartSP);
1631  TemperatureCompensateOnStartS[0].s = TCOnStart ? ISS_ON : ISS_OFF;
1632  TemperatureCompensateOnStartS[1].s = TCOnStart ? ISS_OFF : ISS_ON;
1633  TemperatureCompensateOnStartSP.s = IPS_OK;
1634  IDSetSwitch(&TemperatureCompensateOnStartSP, nullptr);
1635 
1636  // Temperature Coeff A
1637  if (isSimulation())
1638  {
1639  snprintf(response, 32, "TempCo A = %d\n", static_cast<int>(TemperatureParamN[0].value));
1640  nbytes_read = strlen(response);
1641  }
1642  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1643  {
1644  tty_error_msg(errcode, errmsg, MAXRBUF);
1645  LOGF_ERROR("%s", errmsg);
1646  return false;
1647  }
1648 
1649  if (TemperatureCompensateModeS[0].s == ISS_ON)
1650  {
1651  response[nbytes_read - 1] = '\0';
1652  LOGF_DEBUG("RES (%s)", response);
1653 
1654  int TCoeff;
1655  rc = sscanf(response, "%15[^=]=%d", key, &TCoeff);
1656  if (rc != 2)
1657  return false;
1658 
1659  TemperatureParamN[0].value = TCoeff;
1660  }
1661  memset(response, 0, sizeof(response));
1662 
1663  // Temperature Coeff B
1664  if (isSimulation())
1665  {
1666  snprintf(response, 32, "TempCo B = %d\n", static_cast<int>(TemperatureParamN[0].value));
1667  nbytes_read = strlen(response);
1668  }
1669  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1670  {
1671  tty_error_msg(errcode, errmsg, MAXRBUF);
1672  LOGF_ERROR("%s", errmsg);
1673  return false;
1674  }
1675  if (TemperatureCompensateModeS[1].s == ISS_ON)
1676  {
1677  response[nbytes_read - 1] = '\0';
1678  LOGF_DEBUG("RES (%s)", response);
1679 
1680  int TCoeff;
1681  rc = sscanf(response, "%15[^=]=%d", key, &TCoeff);
1682  if (rc != 2)
1683  return false;
1684 
1685  TemperatureParamN[0].value = TCoeff;
1686  }
1687 
1688  memset(response, 0, sizeof(response));
1689 
1690  // Temperature Coeff C
1691  if (isSimulation())
1692  {
1693  snprintf(response, 32, "TempCo C = %d\n", static_cast<int>(TemperatureParamN[0].value));
1694  nbytes_read = strlen(response);
1695  }
1696  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1697  {
1698  tty_error_msg(errcode, errmsg, MAXRBUF);
1699  LOGF_ERROR("%s", errmsg);
1700  return false;
1701  }
1702  if (TemperatureCompensateModeS[2].s == ISS_ON)
1703  {
1704  response[nbytes_read - 1] = '\0';
1705  LOGF_DEBUG("RES (%s)", response);
1706 
1707  int TCoeff;
1708  rc = sscanf(response, "%15[^=]=%d", key, &TCoeff);
1709  if (rc != 2)
1710  return false;
1711 
1712  TemperatureParamN[0].value = TCoeff;
1713  }
1714 
1715  memset(response, 0, sizeof(response));
1716 
1717  // Temperature Coeff D
1718  if (isSimulation())
1719  {
1720  snprintf(response, 32, "TempCo D = %d\n", static_cast<int>(TemperatureParamN[0].value));
1721  nbytes_read = strlen(response);
1722  }
1723  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1724  {
1725  tty_error_msg(errcode, errmsg, MAXRBUF);
1726  LOGF_ERROR("%s", errmsg);
1727  return false;
1728  }
1729  if (TemperatureCompensateModeS[3].s == ISS_ON)
1730  {
1731  response[nbytes_read - 1] = '\0';
1732  LOGF_DEBUG("RES (%s)", response);
1733 
1734  int TCoeff;
1735  rc = sscanf(response, "%15[^=]=%d", key, &TCoeff);
1736  if (rc != 2)
1737  return false;
1738 
1739  TemperatureParamN[0].value = TCoeff;
1740  }
1741 
1742  memset(response, 0, sizeof(response));
1743 
1744  // Temperature Coeff E
1745  if (isSimulation())
1746  {
1747  snprintf(response, 32, "TempCo E = %d\n", static_cast<int>(TemperatureParamN[0].value));
1748  nbytes_read = strlen(response);
1749  }
1750  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1751  {
1752  tty_error_msg(errcode, errmsg, MAXRBUF);
1753  LOGF_ERROR("%s", errmsg);
1754  return false;
1755  }
1756  if (TemperatureCompensateModeS[4].s == ISS_ON)
1757  {
1758  response[nbytes_read - 1] = '\0';
1759  LOGF_DEBUG("RES (%s)", response);
1760 
1761  int TCoeff;
1762  rc = sscanf(response, "%15[^=]=%d", key, &TCoeff);
1763  if (rc != 2)
1764  return false;
1765 
1766  TemperatureParamN[0].value = TCoeff;
1767  }
1768 
1769  memset(response, 0, sizeof(response));
1770 
1771  // Temperature intercepts A
1772  if (isSimulation())
1773  {
1774  snprintf(response, 32, "TempIn A = %d\n", static_cast<int>(TemperatureParamN[1].value));
1775  nbytes_read = strlen(response);
1776  }
1777  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1778  {
1779  tty_error_msg(errcode, errmsg, MAXRBUF);
1780  LOGF_ERROR("%s", errmsg);
1781  return false;
1782  }
1783  if (TemperatureCompensateModeS[0].s == ISS_ON)
1784  {
1785  response[nbytes_read - 1] = '\0';
1786  LOGF_DEBUG("RES (%s)", response);
1787 
1788  int TInter;
1789  rc = sscanf(response, "%15[^=]=%d", key, &TInter);
1790  if (rc != 2)
1791  return false;
1792 
1793  TemperatureParamN[1].value = TInter;
1794  }
1795 
1796  memset(response, 0, sizeof(response));
1797 
1798  // Temperature intercepts B
1799  if (isSimulation())
1800  {
1801  snprintf(response, 32, "TempIn B = %d\n", static_cast<int>(TemperatureParamN[1].value));
1802  nbytes_read = strlen(response);
1803  }
1804  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1805  {
1806  tty_error_msg(errcode, errmsg, MAXRBUF);
1807  LOGF_ERROR("%s", errmsg);
1808  return false;
1809  }
1810  if (TemperatureCompensateModeS[1].s == ISS_ON)
1811  {
1812  response[nbytes_read - 1] = '\0';
1813  LOGF_DEBUG("RES (%s)", response);
1814 
1815  int TInter;
1816  rc = sscanf(response, "%15[^=]=%d", key, &TInter);
1817  if (rc != 2)
1818  return false;
1819 
1820  TemperatureParamN[1].value = TInter;
1821  }
1822 
1823  memset(response, 0, sizeof(response));
1824 
1825  // Temperature intercepts C
1826  if (isSimulation())
1827  {
1828  snprintf(response, 32, "TempIn C = %d\n", static_cast<int>(TemperatureParamN[1].value));
1829  nbytes_read = strlen(response);
1830  }
1831  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1832  {
1833  tty_error_msg(errcode, errmsg, MAXRBUF);
1834  LOGF_ERROR("%s", errmsg);
1835  return false;
1836  }
1837  if (TemperatureCompensateModeS[2].s == ISS_ON)
1838  {
1839  response[nbytes_read - 1] = '\0';
1840  LOGF_DEBUG("RES (%s)", response);
1841 
1842  int TInter;
1843  rc = sscanf(response, "%15[^=]=%d", key, &TInter);
1844  if (rc != 2)
1845  return false;
1846 
1847  TemperatureParamN[1].value = TInter;
1848  }
1849 
1850  memset(response, 0, sizeof(response));
1851 
1852  // Temperature intercepts D
1853  if (isSimulation())
1854  {
1855  snprintf(response, 32, "TempIn D = %d\n", static_cast<int>(TemperatureParamN[1].value));
1856  nbytes_read = strlen(response);
1857  }
1858  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1859  {
1860  tty_error_msg(errcode, errmsg, MAXRBUF);
1861  LOGF_ERROR("%s", errmsg);
1862  return false;
1863  }
1864  if (TemperatureCompensateModeS[3].s == ISS_ON)
1865  {
1866  response[nbytes_read - 1] = '\0';
1867  LOGF_DEBUG("RES (%s)", response);
1868 
1869  int TInter;
1870  rc = sscanf(response, "%15[^=]=%d", key, &TInter);
1871  if (rc != 2)
1872  return false;
1873 
1874  TemperatureParamN[1].value = TInter;
1875  }
1876 
1877  memset(response, 0, sizeof(response));
1878 
1879  // Temperature intercepts E
1880  if (isSimulation())
1881  {
1882  snprintf(response, 32, "TempIn E = %d\n", static_cast<int>(TemperatureParamN[1].value));
1883  nbytes_read = strlen(response);
1884  }
1885  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1886  {
1887  tty_error_msg(errcode, errmsg, MAXRBUF);
1888  LOGF_ERROR("%s", errmsg);
1889  return false;
1890  }
1891  if (TemperatureCompensateModeS[4].s == ISS_ON)
1892  {
1893  response[nbytes_read - 1] = '\0';
1894  LOGF_DEBUG("RES (%s)", response);
1895 
1896  int TInter;
1897  rc = sscanf(response, "%15[^=]=%d", key, &TInter);
1898  if (rc != 2)
1899  return false;
1900 
1901  TemperatureParamN[1].value = TInter;
1902  }
1903 
1904  TemperatureParamNP.s = IPS_OK;
1905  IDSetNumber(&TemperatureParamNP, nullptr);
1906 
1907  memset(response, 0, sizeof(response));
1908 
1909  // StepSize
1910  if (isSimulation())
1911  {
1912  snprintf(response, 32, "StepSize = %d\n", static_cast<int>(StepSizeN[0].value));
1913  nbytes_read = strlen(response);
1914  }
1915  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1916  {
1917  tty_error_msg(errcode, errmsg, MAXRBUF);
1918  LOGF_ERROR("%s", errmsg);
1919  return false;
1920  }
1921  response[nbytes_read - 1] = '\0';
1922  LOGF_DEBUG("RES (%s)", response);
1923 
1924  int valueStepSize;
1925  rc = sscanf(response, "%15[^=]=%d", key, &valueStepSize);
1926  if (rc != 2)
1927  return false;
1928 
1929  StepSizeN[0].value = valueStepSize;
1930  IDSetNumber(&StepSizeNP, nullptr);
1931 
1932  memset(response, 0, sizeof(response));
1933 
1934  // END is reached
1935  memset(response, 0, sizeof(response));
1936  if (isSimulation())
1937  {
1938  strncpy(response, "END\n", 16);
1939  nbytes_read = strlen(response);
1940  }
1941  else if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
1942  {
1943  tty_error_msg(errcode, errmsg, MAXRBUF);
1944  LOGF_ERROR("%s", errmsg);
1945  return false;
1946  }
1947 
1948  if (nbytes_read > 0)
1949  {
1950  response[nbytes_read - 1] = '\0';
1951 
1952  // Display the response to be sure to have read the complet TTY Buffer.
1953  LOGF_DEBUG("RES (%s)", response);
1954  if (strcmp(response, "END"))
1955  return false;
1956  }
1957 
1958  tcflush(PortFD, TCIFLUSH);
1959 
1960  return true;
1961  }
1962  return false;
1963 }
1964 
1965 /************************************************************************************
1966  *
1967 * ***********************************************************************************/
1969 {
1970  char cmd[16];
1971  int errcode = 0;
1972  char errmsg[MAXRBUF];
1973  char response[LYNX_MAX] = {0};
1974  int nbytes_read = 0;
1975  int nbytes_written = 0;
1976 
1977  memset(response, 0, sizeof(response));
1978 
1979  snprintf(cmd, 16, "<%sSCDT%s>", getFocusTarget(), index > 0 ? lynxModels[ModelS[index].name].c_str() : "ZZ");
1980 
1981  LOGF_DEBUG("CMD (%s)", cmd);
1982 
1983  if (isSimulation())
1984  {
1985  strncpy(response, "SET", 16);
1986  nbytes_read = strlen(response) + 1;
1987  }
1988  else
1989  {
1990  tcflush(PortFD, TCIFLUSH);
1991 
1992  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
1993  {
1994  tty_error_msg(errcode, errmsg, MAXRBUF);
1995  LOGF_ERROR("%s", errmsg);
1996  return false;
1997  }
1998 
1999  if (!isResponseOK())
2000  return false;
2001 
2002  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2003  {
2004  tty_error_msg(errcode, errmsg, MAXRBUF);
2005  LOGF_ERROR("%s", errmsg);
2006  return false;
2007  }
2008  }
2009 
2010  if (nbytes_read > 0)
2011  {
2012  response[nbytes_read - 1] = '\0';
2013  LOGF_DEBUG("RES (%s)", response);
2014  tcflush(PortFD, TCIFLUSH);
2015 
2016  if (!strcmp(response, "SET"))
2017  return true;
2018  else
2019  return false;
2020  }
2021 
2022  return false;
2023 }
2024 
2025 /************************************************************************************
2026  *
2027 * ***********************************************************************************/
2028 bool FocusLynxBase::setLedLevel(int level)
2029 // Write via the connected port to the HUB the selected LED intensity level
2030 
2031 {
2032  char cmd[16];
2033  int errcode = 0;
2034  char errmsg[MAXRBUF];
2035  char response[LYNX_MAX] = {0};
2036  int nbytes_read = 0;
2037  int nbytes_written = 0;
2038 
2039  memset(response, 0, sizeof(response));
2040 
2041  snprintf(cmd, 16, "<FHSCLB%d>", level);
2042 
2043  LOGF_DEBUG("CMD (%s)", cmd);
2044 
2045  if (isSimulation())
2046  {
2047  strncpy(response, "SET", 16);
2048  nbytes_read = strlen(response) + 1;
2049  }
2050  else
2051  {
2052  tcflush(PortFD, TCIFLUSH);
2053 
2054  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2055  {
2056  tty_error_msg(errcode, errmsg, MAXRBUF);
2057  LOGF_ERROR("%s", errmsg);
2058  return false;
2059  }
2060 
2061  if (!isResponseOK())
2062  return false;
2063 
2064  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2065  {
2066  tty_error_msg(errcode, errmsg, MAXRBUF);
2067  LOGF_ERROR("%s", errmsg);
2068  return false;
2069  }
2070  }
2071 
2072  if (nbytes_read > 0)
2073  {
2074  response[nbytes_read - 1] = '\0';
2075  LOGF_DEBUG("RES (%s)", response);
2076  tcflush(PortFD, TCIFLUSH);
2077 
2078  if (!strcmp(response, "SET"))
2079  return true;
2080  else
2081  return false;
2082  }
2083 
2084  return false;
2085 }
2086 
2087 /************************************************************************************
2088  *
2089 * ***********************************************************************************/
2090 bool FocusLynxBase::setDeviceNickname(const char *nickname)
2091 // Write via the connected port to the HUB the choiced nikname of the focuser
2092 {
2093  char cmd[LYNX_MAX] = {0};
2094  int errcode = 0;
2095  char errmsg[MAXRBUF];
2096  char response[LYNX_MAX] = {0};
2097  int nbytes_read = 0;
2098  int nbytes_written = 0;
2099 
2100  memset(response, 0, sizeof(response));
2101 
2102  snprintf(cmd, LYNX_MAX, "<%sSCNN%s>", getFocusTarget(), nickname);
2103 
2104  LOGF_DEBUG("CMD (%s)", cmd);
2105 
2106  if (isSimulation())
2107  {
2108  strncpy(response, "SET", 16);
2109  nbytes_read = strlen(response) + 1;
2110  }
2111  else
2112  {
2113  tcflush(PortFD, TCIFLUSH);
2114 
2115  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2116  {
2117  tty_error_msg(errcode, errmsg, MAXRBUF);
2118  LOGF_ERROR("%s", errmsg);
2119  return false;
2120  }
2121 
2122  if (!isResponseOK())
2123  return false;
2124 
2125  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2126  {
2127  tty_error_msg(errcode, errmsg, MAXRBUF);
2128  LOGF_ERROR("%s", errmsg);
2129  return false;
2130  }
2131  }
2132 
2133  if (nbytes_read > 0)
2134  {
2135  response[nbytes_read - 1] = '\0';
2136  LOGF_DEBUG("RES (%s)", response);
2137  tcflush(PortFD, TCIFLUSH);
2138 
2139  if (!strcmp(response, "SET"))
2140  return true;
2141  else
2142  return false;
2143  }
2144 
2145  return false;
2146 }
2147 /************************************************************************************
2148  *
2149 * ***********************************************************************************/
2150 bool FocusLynxBase::home()
2151 {
2152  char cmd[LYNX_MAX] = {0};
2153  int errcode = 0;
2154  char errmsg[MAXRBUF];
2155  char response[LYNX_MAX] = {0};
2156  int nbytes_read = 0;
2157  int nbytes_written = 0;
2158 
2159  memset(response, 0, sizeof(response));
2160 
2161  snprintf(cmd, LYNX_MAX, "<%sHOME>", getFocusTarget());
2162  LOGF_DEBUG("CMD (%s)", cmd);
2163 
2164  if (isSimulation())
2165  {
2166  strncpy(response, "H", 16);
2167  nbytes_read = strlen(response) + 1;
2168  targetPosition = 0;
2169  //FocusAbsPosN[0].value = MaxTravelN[0].value;
2171  IDSetNumber(&FocusAbsPosNP, nullptr);
2172  simStatus[STATUS_HOMING] = ISS_ON;
2173  simStatus[STATUS_HOMED] = ISS_OFF;
2174  simPosition = FocusAbsPosN[0].value;
2175  }
2176  else
2177  {
2178  tcflush(PortFD, TCIFLUSH);
2179 
2180  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2181  {
2182  tty_error_msg(errcode, errmsg, MAXRBUF);
2183  LOGF_ERROR("%s", errmsg);
2184  return false;
2185  }
2186 
2187  if (!isResponseOK())
2188  return false;
2189 
2190  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2191  {
2192  tty_error_msg(errcode, errmsg, MAXRBUF);
2193  LOGF_ERROR("%s", errmsg);
2194  return false;
2195  }
2196  }
2197 
2198  if (nbytes_read > 0)
2199  {
2200  response[nbytes_read - 1] = '\0';
2201  LOGF_DEBUG("RES (%s)", response);
2203  IDSetNumber(&FocusAbsPosNP, nullptr);
2204 
2205  isHoming = true;
2206  LOG_INFO("Focuser is homing...");
2207 
2208  tcflush(PortFD, TCIFLUSH);
2209 
2210  return true;
2211  }
2212 
2213  return false;
2214 }
2215 
2216 /************************************************************************************
2217  *
2218 * ***********************************************************************************/
2219 bool FocusLynxBase::center()
2220 {
2221  char cmd[LYNX_MAX] = {0};
2222  int errcode = 0;
2223  char errmsg[MAXRBUF];
2224  char response[LYNX_MAX] = {0};
2225  int nbytes_read = 0;
2226  int nbytes_written = 0;
2227 
2228  memset(response, 0, sizeof(response));
2229 
2230  snprintf(cmd, LYNX_MAX, "<%sCENTER>", getFocusTarget());
2231  LOGF_DEBUG("CMD (%s)", cmd);
2232 
2233  if (isSimulation())
2234  {
2235  strncpy(response, "M", 16);
2236  nbytes_read = strlen(response) + 1;
2237  simStatus[STATUS_MOVING] = ISS_ON;
2238  targetPosition = FocusAbsPosN[0].max / 2;
2239  }
2240  else
2241  {
2242  tcflush(PortFD, TCIFLUSH);
2243 
2244  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2245  {
2246  tty_error_msg(errcode, errmsg, MAXRBUF);
2247  LOGF_ERROR("%s", errmsg);
2248  return false;
2249  }
2250 
2251  if (!isResponseOK())
2252  return false;
2253 
2254  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2255  {
2256  tty_error_msg(errcode, errmsg, MAXRBUF);
2257  LOGF_ERROR("%s", errmsg);
2258  return false;
2259  }
2260  }
2261 
2262  if (nbytes_read > 0)
2263  {
2264  response[nbytes_read - 1] = '\0';
2265  LOGF_DEBUG("RES (%s)", response);
2266 
2267  LOG_INFO("Focuser moving to center position...");
2268 
2270  IDSetNumber(&FocusAbsPosNP, nullptr);
2271 
2272  tcflush(PortFD, TCIFLUSH);
2273 
2274  return true;
2275  }
2276 
2277  return false;
2278 }
2279 
2280 /************************************************************************************
2281  *
2282 * ***********************************************************************************/
2283 bool FocusLynxBase::setTemperatureCompensation(bool enable)
2284 {
2285  char cmd[16];
2286  int errcode = 0;
2287  char errmsg[MAXRBUF];
2288  char response[LYNX_MAX] = {0};
2289  int nbytes_read = 0;
2290  int nbytes_written = 0;
2291 
2292  memset(response, 0, sizeof(response));
2293 
2294  snprintf(cmd, 16, "<%sSCTE%d>", getFocusTarget(), enable ? 1 : 0);
2295 
2296  LOGF_DEBUG("CMD (%s)", cmd);
2297 
2298  if (isSimulation())
2299  {
2300  strncpy(response, "SET", 16);
2301  nbytes_read = strlen(response) + 1;
2302  }
2303  else
2304  {
2305  tcflush(PortFD, TCIFLUSH);
2306 
2307  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2308  {
2309  tty_error_msg(errcode, errmsg, MAXRBUF);
2310  LOGF_ERROR("%s", errmsg);
2311  return false;
2312  }
2313 
2314  if (!isResponseOK())
2315  return false;
2316 
2317  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2318  {
2319  tty_error_msg(errcode, errmsg, MAXRBUF);
2320  LOGF_ERROR("%s", errmsg);
2321  return false;
2322  }
2323  }
2324 
2325  if (nbytes_read > 0)
2326  {
2327  response[nbytes_read - 1] = '\0';
2328  LOGF_DEBUG("RES (%s)", response);
2329  tcflush(PortFD, TCIFLUSH);
2330 
2331  if (!strcmp(response, "SET"))
2332  return true;
2333  else
2334  return false;
2335  }
2336 
2337  return false;
2338 }
2339 
2340 /************************************************************************************
2341  *
2342 * ***********************************************************************************/
2343 bool FocusLynxBase::setTemperatureCompensationMode(char mode)
2344 {
2345  char cmd[16];
2346  int errcode = 0;
2347  char errmsg[MAXRBUF];
2348  char response[LYNX_MAX] = {0};
2349  int nbytes_read = 0;
2350  int nbytes_written = 0;
2351 
2352  memset(response, 0, sizeof(response));
2353 
2354  snprintf(cmd, 16, "<%sSCTM%c>", getFocusTarget(), mode);
2355 
2356  LOGF_DEBUG("CMD (%s)", cmd);
2357 
2358  if (isSimulation())
2359  {
2360  strncpy(response, "SET", 16);
2361  nbytes_read = strlen(response) + 1;
2362  }
2363  else
2364  {
2365  tcflush(PortFD, TCIFLUSH);
2366 
2367  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2368  {
2369  tty_error_msg(errcode, errmsg, MAXRBUF);
2370  LOGF_ERROR("%s", errmsg);
2371  return false;
2372  }
2373 
2374  if (!isResponseOK())
2375  return false;
2376 
2377  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2378  {
2379  tty_error_msg(errcode, errmsg, MAXRBUF);
2380  LOGF_ERROR("%s", errmsg);
2381  return false;
2382  }
2383  }
2384 
2385  if (nbytes_read > 0)
2386  {
2387  response[nbytes_read - 1] = '\0';
2388  LOGF_DEBUG("RES (%s)", response);
2389  tcflush(PortFD, TCIFLUSH);
2390 
2391  // If OK, the value would be read and update UI properties
2392  if (!strcmp(response, "SET"))
2393  return getFocusTemp();
2394  else
2395  return false;
2396  }
2397 
2398  return false;
2399 }
2400 
2401 /************************************************************************************
2402  *
2403 * ***********************************************************************************/
2404 bool FocusLynxBase::setTemperatureCompensationCoeff(char mode, int16_t coeff)
2405 {
2406  char cmd[16];
2407  int errcode = 0;
2408  char errmsg[MAXRBUF];
2409  char response[LYNX_MAX] = {0};
2410  int nbytes_read = 0;
2411  int nbytes_written = 0;
2412 
2413  memset(response, 0, sizeof(response));
2414 
2415  snprintf(cmd, 16, "<%sSCTC%c%c%04d>", getFocusTarget(), mode, coeff >= 0 ? '+' : '-', static_cast<int>(std::abs(coeff)));
2416 
2417  LOGF_DEBUG("CMD (%s)", cmd);
2418 
2419  if (isSimulation())
2420  {
2421  strncpy(response, "SET", 16);
2422  nbytes_read = strlen(response) + 1;
2423  }
2424  else
2425  {
2426  tcflush(PortFD, TCIFLUSH);
2427 
2428  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2429  {
2430  tty_error_msg(errcode, errmsg, MAXRBUF);
2431  LOGF_ERROR("%s", errmsg);
2432  return false;
2433  }
2434 
2435  if (!isResponseOK())
2436  return false;
2437 
2438  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2439  {
2440  tty_error_msg(errcode, errmsg, MAXRBUF);
2441  LOGF_ERROR("%s", errmsg);
2442  return false;
2443  }
2444  }
2445 
2446  if (nbytes_read > 0)
2447  {
2448  response[nbytes_read - 1] = '\0';
2449  LOGF_DEBUG("RES (%s)", response);
2450  tcflush(PortFD, TCIFLUSH);
2451 
2452  if (!strcmp(response, "SET"))
2453  return true;
2454  else
2455  return false;
2456  }
2457 
2458  return false;
2459 }
2460 
2461 /************************************************************************************
2462  *
2463 * ***********************************************************************************/
2464 bool FocusLynxBase::setTemperatureInceptions(char mode, int32_t inter)
2465 {
2466  char cmd[LYNX_MAX] = {0};
2467  int errcode = 0;
2468  char errmsg[MAXRBUF];
2469  char response[LYNX_MAX] = {0};
2470  int nbytes_read = 0;
2471  int nbytes_written = 0;
2472 
2473  memset(response, 0, sizeof(response));
2474 
2475  snprintf(cmd, LYNX_MAX, "<%sSETINT%c%c%06d>", getFocusTarget(), mode, inter >= 0 ? '+' : '-',
2476  static_cast<int>(std::abs(inter)));
2477 
2478  LOGF_DEBUG("CMD (%s)", cmd);
2479 
2480  if (isSimulation())
2481  {
2482  strncpy(response, "SET", 16);
2483  nbytes_read = strlen(response) + 1;
2484  }
2485  else
2486  {
2487  tcflush(PortFD, TCIFLUSH);
2488 
2489  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2490  {
2491  tty_error_msg(errcode, errmsg, MAXRBUF);
2492  LOGF_ERROR("%s", errmsg);
2493  return false;
2494  }
2495 
2496  if (!isResponseOK())
2497  return false;
2498 
2499  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2500  {
2501  tty_error_msg(errcode, errmsg, MAXRBUF);
2502  LOGF_ERROR("%s", errmsg);
2503  return false;
2504  }
2505  }
2506 
2507  if (nbytes_read > 0)
2508  {
2509  response[nbytes_read - 1] = '\0';
2510  LOGF_DEBUG("RES (%s)", response);
2511  tcflush(PortFD, TCIFLUSH);
2512 
2513  if (!strcmp(response, "SET"))
2514  return true;
2515  else
2516  return false;
2517  }
2518 
2519  return false;
2520 }
2521 
2522 /************************************************************************************
2523  *
2524 * ***********************************************************************************/
2525 bool FocusLynxBase::setTemperatureCompensationOnStart(bool enable)
2526 {
2527  char cmd[16];
2528  int errcode = 0;
2529  char errmsg[MAXRBUF];
2530  char response[LYNX_MAX] = {0};
2531  int nbytes_read = 0;
2532  int nbytes_written = 0;
2533 
2534  memset(response, 0, sizeof(response));
2535 
2536  snprintf(cmd, 16, "<%sSCTS%d>", getFocusTarget(), enable ? 1 : 0);
2537 
2538  LOGF_DEBUG("CMD (%s)", cmd);
2539 
2540  if (isSimulation())
2541  {
2542  strncpy(response, "SET", 16);
2543  nbytes_read = strlen(response) + 1;
2544  }
2545  else
2546  {
2547  tcflush(PortFD, TCIFLUSH);
2548 
2549  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2550  {
2551  tty_error_msg(errcode, errmsg, MAXRBUF);
2552  LOGF_ERROR("%s", errmsg);
2553  return false;
2554  }
2555 
2556  if (!isResponseOK())
2557  return false;
2558 
2559  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2560  {
2561  tty_error_msg(errcode, errmsg, MAXRBUF);
2562  LOGF_ERROR("%s", errmsg);
2563  return false;
2564  }
2565  }
2566 
2567  if (nbytes_read > 0)
2568  {
2569  response[nbytes_read - 1] = '\0';
2570  LOGF_DEBUG("RES (%s)", response);
2571  tcflush(PortFD, TCIFLUSH);
2572 
2573  if (!strcmp(response, "SET"))
2574  return true;
2575  else
2576  return false;
2577  }
2578 
2579  return false;
2580 }
2581 
2582 /************************************************************************************
2583  *
2584 * ***********************************************************************************/
2585 //bool FocusLynxBase::setBacklashCompensation(bool enable)
2587 {
2588  char cmd[16];
2589  int errcode = 0;
2590  char errmsg[MAXRBUF];
2591  char response[LYNX_MAX] = {0};
2592  int nbytes_read = 0;
2593  int nbytes_written = 0;
2594 
2595  memset(response, 0, sizeof(response));
2596 
2597  snprintf(cmd, 16, "<%sSCBE%d>", getFocusTarget(), enabled ? 1 : 0);
2598 
2599  LOGF_DEBUG("CMD (%s)", cmd);
2600 
2601  if (isSimulation())
2602  {
2603  strncpy(response, "SET", 16);
2604  nbytes_read = strlen(response) + 1;
2605  }
2606  else
2607  {
2608  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2609  {
2610  tty_error_msg(errcode, errmsg, MAXRBUF);
2611  LOGF_ERROR("%s", errmsg);
2612  return false;
2613  }
2614 
2615  if (!isResponseOK())
2616  return false;
2617 
2618  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2619  {
2620  tty_error_msg(errcode, errmsg, MAXRBUF);
2621  LOGF_ERROR("%s", errmsg);
2622  return false;
2623  }
2624  }
2625 
2626  if (nbytes_read > 0)
2627  {
2628  response[nbytes_read - 1] = '\0';
2629  LOGF_DEBUG("RES (%s)", response);
2630  tcflush(PortFD, TCIFLUSH);
2631 
2632  if (!strcmp(response, "SET"))
2633  return true;
2634  else
2635  return false;
2636  }
2637 
2638  return false;
2639 }
2640 
2641 /************************************************************************************
2642  *
2643 * ***********************************************************************************/
2644 //bool FocusLynxBase::setFocusBacklashSteps(uint16_t steps)
2646 {
2647  char cmd[16];
2648  int errcode = 0;
2649  char errmsg[MAXRBUF];
2650  char response[LYNX_MAX] = {0};
2651  int nbytes_read = 0;
2652  int nbytes_written = 0;
2653 
2654  memset(response, 0, sizeof(response));
2655 
2656  snprintf(cmd, 16, "<%sSCBS%02d>", getFocusTarget(), steps);
2657 
2658  LOGF_DEBUG("CMD (%s)", cmd);
2659 
2660  if (isSimulation())
2661  {
2662  strncpy(response, "SET", 16);
2663  nbytes_read = strlen(response) + 1;
2664  }
2665  else
2666  {
2667  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2668  {
2669  tty_error_msg(errcode, errmsg, MAXRBUF);
2670  LOGF_ERROR("%s", errmsg);
2671  return false;
2672  }
2673 
2674  if (!isResponseOK())
2675  return false;
2676 
2677  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2678  {
2679  tty_error_msg(errcode, errmsg, MAXRBUF);
2680  LOGF_ERROR("%s", errmsg);
2681  return false;
2682  }
2683  }
2684 
2685  if (nbytes_read > 0)
2686  {
2687  response[nbytes_read - 1] = '\0';
2688  LOGF_DEBUG("RES (%s)", response);
2689  tcflush(PortFD, TCIFLUSH);
2690 
2691  if (!strcmp(response, "SET"))
2692  return true;
2693  else
2694  return false;
2695  }
2696 
2697  return false;
2698 }
2699 
2700 /************************************************************************************
2701  *
2702 * ***********************************************************************************/
2704 {
2705  char cmd[16];
2706  int errcode = 0;
2707  char errmsg[MAXRBUF];
2708  char response[LYNX_MAX] = {0};
2709  int nbytes_read = 0;
2710  int nbytes_written = 0;
2711 
2712  memset(response, 0, sizeof(response));
2713 
2714  snprintf(cmd, 16, "<%sREVERSE%d>", getFocusTarget(), enabled ? 1 : 0);
2715 
2716  LOGF_DEBUG("CMD (%s)", cmd);
2717 
2718  if (isSimulation())
2719  {
2720  strncpy(response, "SET", 16);
2721  nbytes_read = strlen(response) + 1;
2722  simStatus[STATUS_REVERSE] = enabled ? ISS_ON : ISS_OFF;
2723  }
2724  else
2725  {
2726  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2727  {
2728  tty_error_msg(errcode, errmsg, MAXRBUF);
2729  LOGF_ERROR("%s", errmsg);
2730  return false;
2731  }
2732 
2733  if (!isResponseOK())
2734  return false;
2735 
2736  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2737  {
2738  tty_error_msg(errcode, errmsg, MAXRBUF);
2739  LOGF_ERROR("%s", errmsg);
2740  return false;
2741  }
2742  }
2743 
2744  if (nbytes_read > 0)
2745  {
2746  response[nbytes_read - 1] = '\0';
2747  LOGF_DEBUG("RES (%s)", response);
2748  tcflush(PortFD, TCIFLUSH);
2749 
2750  if (!strcmp(response, "SET"))
2751  return true;
2752  else
2753  return false;
2754  }
2755 
2756  return false;
2757 }
2758 
2759 /************************************************************************************
2760  *
2761 * ***********************************************************************************/
2762 bool FocusLynxBase::SyncFocuser(uint32_t ticks)
2763 {
2764  char cmd[LYNX_MAX] = {0};
2765  int errcode = 0;
2766  char errmsg[MAXRBUF];
2767  char response[LYNX_MAX] = {0};
2768  int nbytes_read = 0;
2769  int nbytes_written = 0;
2770 
2771  memset(response, 0, sizeof(response));
2772 
2773  snprintf(cmd, LYNX_MAX, "<%sSCCP%06d>", getFocusTarget(), ticks);
2774  LOGF_DEBUG("CMD (%s)", cmd);
2775 
2776  if (isSimulation())
2777  {
2778  simPosition = ticks;
2779  strncpy(response, "SET", 16);
2780  nbytes_read = strlen(response) + 1;
2781  }
2782  else
2783  {
2784  tcflush(PortFD, TCIFLUSH);
2785 
2786  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2787  {
2788  tty_error_msg(errcode, errmsg, MAXRBUF);
2789  LOGF_ERROR("%s", errmsg);
2790  return false;
2791  }
2792 
2793  if (!isResponseOK())
2794  return false;
2795 
2796  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2797  {
2798  tty_error_msg(errcode, errmsg, MAXRBUF);
2799  LOGF_ERROR("%s", errmsg);
2800  return false;
2801  }
2802  }
2803 
2804  if (nbytes_read > 0)
2805  {
2806  response[nbytes_read - 1] = '\0';
2807  LOGF_DEBUG("RES (%s)", response);
2808  tcflush(PortFD, TCIFLUSH);
2809 
2810  if (!strcmp(response, "SET"))
2811  {
2812  LOGF_INFO("Setting current position to %d", ticks);
2813  return true;
2814  }
2815  else
2816  return false;
2817  }
2818  return false;
2819 }
2820 
2821 /************************************************************************************
2822  *
2823 * ***********************************************************************************/
2824 //bool FocusLynxBase::setMaxTravel(uint16_t travel)
2826 {
2827  char cmd[LYNX_MAX] = {0};
2828  int errcode = 0;
2829  char errmsg[MAXRBUF];
2830  char response[LYNX_MAX] = {0};
2831  int nbytes_read = 0;
2832  int nbytes_written = 0;
2833 
2834  memset(response, 0, sizeof(response));
2835 
2836  snprintf(cmd, LYNX_MAX, "<%sSETMAX%06d>", getFocusTarget(), ticks);
2837  LOGF_DEBUG("CMD (%s)", cmd);
2838 
2839  SyncPresets(ticks);
2840 
2841  if (isSimulation())
2842  {
2843  strncpy(response, "SET", 16);
2844  nbytes_read = strlen(response) + 1;
2845  }
2846  else
2847  {
2848  tcflush(PortFD, TCIFLUSH);
2849 
2850  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2851  {
2852  tty_error_msg(errcode, errmsg, MAXRBUF);
2853  LOGF_ERROR("%s", errmsg);
2854  return false;
2855  }
2856 
2857  if (!isResponseOK())
2858  return false;
2859 
2860  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2861  {
2862  tty_error_msg(errcode, errmsg, MAXRBUF);
2863  LOGF_ERROR("%s", errmsg);
2864  return false;
2865  }
2866  }
2867 
2868  if (nbytes_read > 0)
2869  {
2870  response[nbytes_read - 1] = '\0';
2871  LOGF_DEBUG("RES (%s)", response);
2872  tcflush(PortFD, TCIFLUSH);
2873 
2874  if (!strcmp(response, "SET"))
2875  {
2876  getFocusConfig();
2877  return true;
2878  }
2879  else
2880  return false;
2881  }
2882 
2883  return false;
2884 }
2885 
2886 /************************************************************************************
2887  *
2888 * ***********************************************************************************/
2889 bool FocusLynxBase::setStepSize(uint16_t stepsize)
2890 {
2891  char cmd[LYNX_MAX] = {0};
2892  int errcode = 0;
2893  char errmsg[MAXRBUF];
2894  char response[LYNX_MAX] = {0};
2895  int nbytes_read = 0;
2896  int nbytes_written = 0;
2897 
2898  memset(response, 0, sizeof(response));
2899 
2900  snprintf(cmd, LYNX_MAX, "<%sSETFSS%06d>", getFocusTarget(), stepsize);
2901  LOGF_DEBUG("CMD (%s)", cmd);
2902 
2903  if (isSimulation())
2904  {
2905  strncpy(response, "SET", 16);
2906  nbytes_read = strlen(response) + 1;
2907  }
2908  else
2909  {
2910  tcflush(PortFD, TCIFLUSH);
2911 
2912  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2913  {
2914  tty_error_msg(errcode, errmsg, MAXRBUF);
2915  LOGF_ERROR("%s", errmsg);
2916  return false;
2917  }
2918 
2919  if (!isResponseOK())
2920  return false;
2921 
2922  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2923  {
2924  tty_error_msg(errcode, errmsg, MAXRBUF);
2925  LOGF_ERROR("%s", errmsg);
2926  return false;
2927  }
2928  }
2929 
2930  if (nbytes_read > 0)
2931  {
2932  response[nbytes_read - 1] = '\0';
2933  LOGF_DEBUG("RES (%s)", response);
2934  tcflush(PortFD, TCIFLUSH);
2935 
2936  if (!strcmp(response, "SET"))
2937  {
2938  getFocusConfig();
2939  return true;
2940  }
2941  else
2942  return false;
2943  }
2944 
2945  return false;
2946 }
2947 
2948 /************************************************************************************
2949  *
2950 * ***********************************************************************************/
2951 bool FocusLynxBase::resetFactory()
2952 {
2953  char cmd[LYNX_MAX] = {0};
2954  int errcode = 0;
2955  char errmsg[MAXRBUF];
2956  char response[LYNX_MAX] = {0};
2957  int nbytes_read = 0;
2958  int nbytes_written = 0;
2959 
2960  memset(response, 0, sizeof(response));
2961 
2962  snprintf(cmd, LYNX_MAX, "<%sRESET>", getFocusTarget());
2963  LOGF_DEBUG("CMD (%s)", cmd);
2964 
2965  if (isSimulation())
2966  {
2967  strncpy(response, "SET", 16);
2968  nbytes_read = strlen(response) + 1;
2969  }
2970  else
2971  {
2972  tcflush(PortFD, TCIFLUSH);
2973 
2974  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
2975  {
2976  tty_error_msg(errcode, errmsg, MAXRBUF);
2977  LOGF_ERROR("%s", errmsg);
2978  return false;
2979  }
2980 
2981  if (!isResponseOK())
2982  return false;
2983 
2984  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
2985  {
2986  tty_error_msg(errcode, errmsg, MAXRBUF);
2987  LOGF_ERROR("%s", errmsg);
2988  return false;
2989  }
2990  }
2991 
2992  if (nbytes_read > 0)
2993  {
2994  response[nbytes_read - 1] = '\0';
2995  LOGF_DEBUG("RES (%s)", response);
2996  tcflush(PortFD, TCIFLUSH);
2997 
2998  if (!strcmp(response, "SET"))
2999  {
3000  getFocusConfig();
3001  return true;
3002  }
3003  else
3004  return false;
3005  }
3006 
3007  return false;
3008 }
3009 
3010 /************************************************************************************
3011  *
3012 * ***********************************************************************************/
3014 {
3015  int errcode = 0;
3016  char errmsg[MAXRBUF];
3017  char response[LYNX_MAX] = {0};
3018  int nbytes_read = 0;
3019 
3020  memset(response, 0, sizeof(response));
3021 
3022  if (isSimulation())
3023  {
3024  strcpy(response, "!");
3025  nbytes_read = strlen(response) + 1;
3026  }
3027  else
3028  {
3029  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
3030  {
3031  tty_error_msg(errcode, errmsg, MAXRBUF);
3032  LOGF_ERROR("TTY error: %s", errmsg);
3033  return false;
3034  }
3035  }
3036 
3037  if (nbytes_read > 0)
3038  {
3039  response[nbytes_read - 1] = '\0';
3040  LOGF_DEBUG("RES (%s)", response);
3041 
3042  if (!strcmp(response, "!"))
3043  return true;
3044  else
3045  {
3046  memset(response, 0, sizeof(response));
3047  while (strstr(response, "END") == nullptr)
3048  {
3049  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
3050  {
3051  tty_error_msg(errcode, errmsg, MAXRBUF);
3052  LOGF_ERROR("TTY error: %s", errmsg);
3053  return false;
3054  }
3055  response[nbytes_read - 1] = '\0';
3056  LOGF_ERROR("Controller error: %s", response);
3057  }
3058 
3059  return false;
3060  }
3061  }
3062  return true;
3063 }
3064 
3065 /************************************************************************************
3066 *
3067 * ***********************************************************************************/
3068 IPState FocusLynxBase::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
3069 {
3070  char cmd[16];
3071  int errcode = 0;
3072  char errmsg[MAXRBUF];
3073  char response[LYNX_MAX] = {0};
3074  int nbytes_read = 0;
3075  int nbytes_written = 0;
3076 
3077  memset(response, 0, sizeof(response));
3078 
3079  snprintf(cmd, 16, "<%sM%cR%c>", getFocusTarget(), (dir == FOCUS_INWARD) ? 'I' : 'O', (speed == 0) ? '0' : '1');
3080 
3081  LOGF_DEBUG("CMD (%s)", cmd);
3082 
3083  if (isSimulation())
3084  {
3085  strncpy(response, "M", 16);
3086  nbytes_read = strlen(response) + 1;
3087  }
3088  else
3089  {
3090  tcflush(PortFD, TCIFLUSH);
3091 
3092  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
3093  {
3094  tty_error_msg(errcode, errmsg, MAXRBUF);
3095  LOGF_ERROR("%s", errmsg);
3096  return IPS_ALERT;
3097  }
3098 
3099  if (!isResponseOK())
3100  return IPS_ALERT;
3101 
3102  gettimeofday(&focusMoveStart, nullptr);
3103  focusMoveRequest = duration / 1000.0;
3104 
3105  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
3106  {
3107  tty_error_msg(errcode, errmsg, MAXRBUF);
3108  LOGF_ERROR("%s", errmsg);
3109  return IPS_ALERT;
3110  }
3111  }
3112 
3113  if (nbytes_read > 0)
3114  {
3115  response[nbytes_read - 1] = '\0';
3116  LOGF_DEBUG("RES (%s)", response);
3117 
3118  if (duration <= getCurrentPollingPeriod())
3119  {
3120  usleep(getCurrentPollingPeriod() * 1000);
3121  AbortFocuser();
3122  return IPS_OK;
3123  }
3124 
3125  tcflush(PortFD, TCIFLUSH);
3126 
3127  return IPS_BUSY;
3128  }
3129 
3130  return IPS_ALERT;
3131 }
3132 
3133 /************************************************************************************
3134 *
3135 * ***********************************************************************************/
3137 {
3138  char cmd[LYNX_MAX] = {0};
3139  int errcode = 0;
3140  char errmsg[MAXRBUF];
3141  char response[LYNX_MAX] = {0};
3142  int nbytes_read = 0;
3143  int nbytes_written = 0;
3144 
3145  targetPosition = targetTicks;
3146 
3147  memset(response, 0, sizeof(response));
3148 
3149  snprintf(cmd, LYNX_MAX, "<%sMA%06d>", getFocusTarget(), targetTicks);
3150 
3151  LOGF_DEBUG("CMD (%s)", cmd);
3152 
3153  if (isSimulation())
3154  {
3155  strncpy(response, "M", 16);
3156  nbytes_read = strlen(response) + 1;
3157  simStatus[STATUS_MOVING] = ISS_ON;
3158  }
3159  else
3160  {
3161  tcflush(PortFD, TCIFLUSH);
3162 
3163  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
3164  {
3165  tty_error_msg(errcode, errmsg, MAXRBUF);
3166  LOGF_ERROR("%s", errmsg);
3167  return IPS_ALERT;
3168  }
3169 
3170  if (!isResponseOK())
3171  return IPS_ALERT;
3172 
3173  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
3174  {
3175  tty_error_msg(errcode, errmsg, MAXRBUF);
3176  LOGF_ERROR("%s", errmsg);
3177  return IPS_ALERT;
3178  }
3179  }
3180 
3181  if (nbytes_read > 0)
3182  {
3183  response[nbytes_read - 1] = '\0';
3184  LOGF_DEBUG("RES (%s)", response);
3185 
3187 
3188  tcflush(PortFD, TCIFLUSH);
3189 
3190  return IPS_BUSY;
3191  }
3192 
3193  return IPS_ALERT;
3194 }
3195 
3196 /************************************************************************************
3197 *
3198 * ***********************************************************************************/
3200 {
3201  uint32_t newPosition = 0;
3202 
3203  if (dir == FOCUS_INWARD)
3204  newPosition = FocusAbsPosN[0].value - ticks;
3205  else
3206  newPosition = FocusAbsPosN[0].value + ticks;
3207 
3208  return MoveAbsFocuser(newPosition);
3209 }
3210 
3211 /************************************************************************************
3212 *
3213 * ***********************************************************************************/
3215 {
3216  if (!isConnected())
3217  return;
3218 
3219  if (configurationComplete == false)
3220  {
3222  return;
3223  }
3224 
3225  bool statusrc = false;
3226  for (int i = 0; i < 2; i++)
3227  {
3228  statusrc = getFocusStatus();
3229  if (statusrc)
3230  break;
3231  }
3232 
3233  if (statusrc == false)
3234  {
3235  LOG_WARN("Unable to read focuser status....");
3237  return;
3238  }
3239 
3241  {
3242  if (isSimulation())
3243  {
3244  if (FocusAbsPosN[0].value < targetPosition)
3245  simPosition += 100;
3246  else
3247  simPosition -= 100;
3248 
3249  simStatus[STATUS_MOVING] = ISS_ON;
3250 
3251  if (std::abs(static_cast<int64_t>(simPosition) - static_cast<int64_t>(targetPosition)) < 100)
3252  {
3253  FocusAbsPosN[0].value = targetPosition;
3254  simPosition = FocusAbsPosN[0].value;
3255  simStatus[STATUS_MOVING] = ISS_OFF;
3256  StatusL[STATUS_MOVING].s = IPS_IDLE;
3257  if (simStatus[STATUS_HOMING] == ISS_ON)
3258  {
3259  StatusL[STATUS_HOMED].s = IPS_OK;
3260  StatusL[STATUS_HOMING].s = IPS_IDLE;
3261  simStatus[STATUS_HOMING] = ISS_OFF;
3262  simStatus[STATUS_HOMED] = ISS_ON;
3263  }
3264  }
3265  else
3266  StatusL[STATUS_MOVING].s = IPS_BUSY;
3267  IDSetLight(&StatusLP, nullptr);
3268  }
3269 
3270  if (isHoming && StatusL[STATUS_HOMED].s == IPS_OK)
3271  {
3272  isHoming = false;
3273  GotoSP.s = IPS_OK;
3274  IUResetSwitch(&GotoSP);
3275  GotoS[GOTO_HOME].s = ISS_ON;
3276  IDSetSwitch(&GotoSP, nullptr);
3278  IDSetNumber(&FocusRelPosNP, nullptr);
3279  LOG_INFO("Focuser completed home.");
3280  if (isSimulation())
3281  center();
3282  }
3283  else if (StatusL[STATUS_MOVING].s == IPS_IDLE)
3284  {
3287  IDSetNumber(&FocusAbsPosNP, nullptr);
3288  IDSetNumber(&FocusRelPosNP, nullptr);
3289  if (GotoSP.s == IPS_BUSY)
3290  {
3291  IUResetSwitch(&GotoSP);
3292  GotoSP.s = IPS_OK;
3293  IDSetSwitch(&GotoSP, nullptr);
3294  }
3295  LOG_INFO("Focuser reached requested position.");
3296  }
3297  else if (StatusL[STATUS_MOVING].s == IPS_BUSY && focusMoveRequest > 0)
3298  {
3299  float remaining = calcTimeLeft(focusMoveStart, focusMoveRequest);
3300 
3301  if (remaining < getCurrentPollingPeriod())
3302  {
3303  sleep(remaining);
3304  AbortFocuser();
3305  focusMoveRequest = 0;
3306  }
3307  }
3308  }
3309  if (StatusL[STATUS_HOMING].s == IPS_BUSY && GotoSP.s != IPS_BUSY)
3310  {
3311  GotoSP.s = IPS_BUSY;
3312  IDSetSwitch(&GotoSP, nullptr);
3313  }
3314 
3316 }
3317 
3318 /************************************************************************************
3319  *
3320 * ***********************************************************************************/
3322 {
3323  char cmd[LYNX_MAX] = {0};
3324  int errcode = 0;
3325  char errmsg[MAXRBUF];
3326  char response[LYNX_MAX] = {0};
3327  int nbytes_read = 0;
3328  int nbytes_written = 0;
3329 
3330  memset(response, 0, sizeof(response));
3331  snprintf(cmd, LYNX_MAX, "<%sHALT>", getFocusTarget());
3332  LOGF_DEBUG("CMD (%s)", cmd);
3333 
3334  if (isSimulation())
3335  {
3336  strncpy(response, "HALTED", 16);
3337  nbytes_read = strlen(response) + 1;
3338  simStatus[STATUS_MOVING] = ISS_OFF;
3339  simStatus[STATUS_HOMING] = ISS_OFF;
3340  }
3341  else
3342  {
3343  tcflush(PortFD, TCIFLUSH);
3344 
3345  if ((errcode = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
3346  {
3347  tty_error_msg(errcode, errmsg, MAXRBUF);
3348  LOGF_ERROR("%s", errmsg);
3349  return false;
3350  }
3351 
3352  if (!isResponseOK())
3353  return false;
3354 
3355  if ((errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
3356  {
3357  tty_error_msg(errcode, errmsg, MAXRBUF);
3358  LOGF_ERROR("%s", errmsg);
3359  return false;
3360  }
3361  }
3362 
3363  if (nbytes_read > 0)
3364  {
3365  response[nbytes_read - 1] = '\0';
3366  LOGF_DEBUG("RES (%s)", response);
3367 
3368  if (FocusRelPosNP.s == IPS_BUSY)
3369  {
3371  IDSetNumber(&FocusRelPosNP, nullptr);
3372  }
3373 
3376  GotoSP.s = IPS_IDLE;
3377  IUResetSwitch(&GotoSP);
3378  IDSetNumber(&FocusTimerNP, nullptr);
3379  IDSetNumber(&FocusAbsPosNP, nullptr);
3380  IDSetSwitch(&GotoSP, nullptr);
3381 
3382  tcflush(PortFD, TCIFLUSH);
3383 
3384  return true;
3385  }
3386 
3387  return false;
3388 }
3389 
3390 /************************************************************************************
3391  *
3392 * ***********************************************************************************/
3393 float FocusLynxBase::calcTimeLeft(timeval start, float req)
3394 {
3395  double timesince;
3396  double timeleft;
3397  struct timeval now
3398  {
3399  0, 0
3400  };
3401  gettimeofday(&now, nullptr);
3402 
3403  timesince =
3404  static_cast<int>((now.tv_sec * 1000.0 + now.tv_usec / 1000)) - static_cast<int>((start.tv_sec * 1000.0 + start.tv_usec /
3405  1000));
3406  timesince = timesince / 1000;
3407  timeleft = req - timesince;
3408  return timeleft;
3409 }
3410 
3411 /************************************************************************************
3412  *
3413 * ***********************************************************************************/
3415 {
3417 
3419  IUSaveConfigSwitch(fp, &TemperatureCompensateSP);
3420  IUSaveConfigSwitch(fp, &TemperatureCompensateOnStartSP);
3421  //IUSaveConfigSwitch(fp, &ReverseSP);
3422  IUSaveConfigNumber(fp, &TemperatureNP);
3423  IUSaveConfigSwitch(fp, &TemperatureCompensateModeSP);
3424  //IUSaveConfigSwitch(fp, &FocusBacklashSP);
3425  //IUSaveConfigNumber(fp, &FocusBacklashNP);
3426  IUSaveConfigNumber(fp, &StepSizeNP);
3427 
3428  return true;
3429 }
3430 
3431 /************************************************************************************
3432 *
3433 ************************************************************************************/
3434 bool FocusLynxBase::loadConfig(bool silent, const char *property)
3435 {
3436  bool result = true;
3437 
3438  if (property == nullptr)
3439  {
3440  // Need to know the user choice for this option not store in HUB
3441  result = INDI::DefaultDevice::loadConfig(silent, "Presets") && result;
3442  if (isSimulation())
3443  {
3444  // Only load for simulation, otherwise got from the HUB
3445  result = (INDI::DefaultDevice::loadConfig(silent, "MODEL") && result);
3446  result = (INDI::DefaultDevice::loadConfig(silent, "T. COMPENSATION") && result);
3447  result = (INDI::DefaultDevice::loadConfig(silent, "T. COMPENSATION @START") && result);
3448  result = (INDI::DefaultDevice::loadConfig(silent, "REVERSE") && result);
3449  result = (INDI::DefaultDevice::loadConfig(silent, "T. COEFF") && result);
3450  result = (INDI::DefaultDevice::loadConfig(silent, "COMPENSATE MODE") && result);
3451  // result = (INDI::DefaultDevice::loadConfig(silent, "BACKLASH COMPENSATION") && result);
3452  // result = (INDI::DefaultDevice::loadConfig(silent, "BACKLASH") && result);
3453  result = (INDI::DefaultDevice::loadConfig(silent, "MAX TRAVEL") && result);
3454  result = (INDI::DefaultDevice::loadConfig(silent, "STEP SIZE") && result);
3455  result = (INDI::DefaultDevice::loadConfig(silent, "T. PARAMETERS") && result);
3456  }
3457  }
3458  else
3459  result = INDI::DefaultDevice::loadConfig(silent, property);
3460 
3461  return result;
3462 }
3463 
3464 /************************************************************************************
3465  *
3466 * ***********************************************************************************/
3468 {
3469  INDI_UNUSED(enable);
3470  //tty_set_debug(enable ? 1 : 0);
3471 }
3472 
3473 /************************************************************************************
3474  *
3475 * ***********************************************************************************/
3476 void FocusLynxBase::setFocusTarget(const char *target)
3477 // Use to set the string of the private char[] focusTarget
3478 {
3479  strncpy(focusTarget, target, 8);
3480 }
3481 
3482 /************************************************************************************
3483  *
3484 * ***********************************************************************************/
3486 // Use to get the string of the private char[] focusTarget
3487 {
3488  return focusTarget;
3489 }
3490 
3491 /************************************************************************************
3492  *
3493 * ***********************************************************************************/
3494 int FocusLynxBase::getVersion(int *major, int *minor, int *sub)
3495 {
3496  INDI_UNUSED(major);
3497  INDI_UNUSED(minor);
3498  INDI_UNUSED(sub);
3499  /* For future use of implementation of new firmware 2.0.0
3500  * and give ability to keep compatible to actual 1.0.9
3501  * Will be to avoid calling to new functions
3502  * Not yet implemented in this version of the driver
3503  */
3504  char sMajor[8], sMinor[8], sSub[8];
3505  int rc = sscanf(version, "%[^.].%[^.].%s", sMajor, sMinor, sSub);
3506 
3507  LOGF_DEBUG("Version major: %s, minor: %s, subversion: %s", sMajor, sMinor, sSub);
3508  *major = atoi(sMajor);
3509  *minor = atoi(sMinor);
3510  *sub = atoi(sSub);
3511  if (rc == 3)
3512  return *major;
3513  return 0; // 0 Means error in this case
3514 }
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
INumberVectorProperty LedNP
virtual int getVersion(int *major, int *minor, int *sub)
virtual const char * getDefaultName() override
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
INumber LedN[1]
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
ISwitchVectorProperty ModelSP
char version[16]
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
ISwitch * ModelS
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
bool configurationComplete
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
bool setDeviceType(int index)
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual IPState MoveAbsFocuser(uint32_t targetPosition) override
MoveFocuser the focuser to an absolute position.
void setFocusTarget(const char *target)
const char * getFocusTarget()
virtual bool loadConfig(bool silent, const char *property) override
Load the last saved configuration file.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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 addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INumberVectorProperty FocusSyncNP
INumberVectorProperty FocusBacklashNP
ISwitchVectorProperty FocusBacklashSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
INumberVectorProperty FocusTimerNP
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumberVectorProperty FocusMaxPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indifocuser.cpp:95
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual void SyncPresets(uint32_t ticks)
syncPresets Updates the min/max/step range of the preset as per the maximum name of Absolute Focus Tr...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
#define FOCUS_SETTINGS_TAB
Definition: dmfc.cpp:34
#define LYNXFOCUS_TIMEOUT
Definition: focuslynxbase.h:39
#define FOCUS_STATUS_TAB
Definition: focuslynxbase.h:45
#define VERSION
Definition: ifwoptec.h:23
#define SUBVERSION
Definition: ifwoptec.h:24
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_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
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
@ 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 IUFillLight(ILight *lp, const char *name, const char *label, IPState s)
Assign attributes for a light property. The light's auxiliary elements will be set to NULL.
Definition: indidevapi.c:169
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 IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char *dev, const char *name, const char *label, const char *group, IPState s)
Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:255
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:291
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition: indidevapi.c:108
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidevapi.c:198
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
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
Definition: indidriver.c:1251
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 IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1296
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_WARN(txt)
Definition: indilogger.h:73
#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 MAXRBUF
Definition: indiserver.cpp:102
std::vector< uint8_t > buffer
@ key
the parser read a key of a value in an object
__u8 cmd[4]
Definition: pwc-ioctl.h:2
One switch descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:421
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250