Instrument Neutral Distributed Interface INDI  2.0.2
tcfs.cpp
Go to the documentation of this file.
1 /*
2  INDI Driver for Optec TCF-S Focuser
3 
4  Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 
20 */
21 
22 #include "tcfs.h"
23 
24 #include "indicom.h"
26 
27 #include <cmath>
28 #include <memory>
29 #include <cstring>
30 #include <termios.h>
31 
32 #define mydev "Optec TCF-S"
33 #define currentPosition FocusAbsPosN[0].value
34 
35 // We declare an auto pointer to TCFS.
36 static std::unique_ptr<TCFS> tcfs(new TCFS());
37 
38 /****************************************************************
39 **
40 **
41 *****************************************************************/
43 {
44  currentMode = MANUAL;
46 
47  setVersion(0, 4);
48 }
49 
50 /****************************************************************
51 **
52 **
53 *****************************************************************/
55 {
56  //LOGF_DEBUG("%s %s",__FUNCTION__, me);
58 
59  // Set upper limit for TCF-S3 focuser
60  if (strcmp(me, "indi_tcfs3_focus") == 0)
61  {
62  isTCFS3 = true;
63 
64  FocusMaxPosN[0].max = 9999;
65  FocusAbsPosN[0].max = 9999;
66  FocusRelPosN[0].max = 2000;
67  FocusRelPosN[0].step = 100;
68  FocusAbsPosN[0].step = 100;
69  FocusRelPosN[0].value = 0;
70  LOG_DEBUG("TCF-S3 detected. Updating maximum position value to 9999.");
71  }
72  else
73  {
74  isTCFS3 = false;
75 
76  FocusMaxPosN[0].max = 7000;
77  FocusAbsPosN[0].max = 7000;
78  FocusRelPosN[0].max = 2000;
79  FocusRelPosN[0].step = 100;
80  FocusAbsPosN[0].step = 100;
81  FocusRelPosN[0].value = 0;
82  LOG_DEBUG("TCF-S detected. Updating maximum position value to 7000.");
83  }
84 
85  IUFillSwitch(&FocusModeS[0], "Manual", "", ISS_ON);
86  IUFillSwitch(&FocusModeS[1], "Auto A", "", ISS_OFF);
87  IUFillSwitch(&FocusModeS[2], "Auto B", "", ISS_OFF);
88  IUFillSwitchVector(&FocusModeSP, FocusModeS, 3, getDeviceName(), "FOCUS_MODE", "Mode", "Main Control", IP_RW,
89  ISR_1OFMANY, 0, IPS_IDLE);
90 
91  IUFillSwitch(&FocusPowerS[0], "FOCUS_SLEEP", "Sleep", ISS_OFF);
92  IUFillSwitch(&FocusPowerS[1], "FOCUS_WAKEUP", "Wake up", ISS_OFF);
93  IUFillSwitchVector(&FocusPowerSP, FocusPowerS, 2, getDeviceName(), "FOCUS_POWER", "Power", "Operation", IP_RW,
94  ISR_ATMOST1, 0, IPS_IDLE);
95 
96  IUFillSwitch(&FocusGotoS[0], "FOCUS_MIN", "Min", ISS_OFF);
97  IUFillSwitch(&FocusGotoS[1], "FOCUS_CENTER", "Center", ISS_OFF);
98  IUFillSwitch(&FocusGotoS[2], "FOCUS_MAX", "Max", ISS_OFF);
99  IUFillSwitch(&FocusGotoS[3], "FOCUS_HOME", "Home", ISS_OFF);
100  IUFillSwitchVector(&FocusGotoSP, FocusGotoS, 4, getDeviceName(), "FOCUS_GOTO", "Go to", "Main Control", IP_RW,
101  ISR_ATMOST1, 0, IPS_IDLE);
102 
103  IUFillNumber(&FocusTemperatureN[0], "FOCUS_TEMPERATURE_VALUE", "Temperature (c)", "%.3f", -50.0, 80, 0, 0);
104  IUFillNumberVector(&FocusTemperatureNP, FocusTemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Probe", "Operation",
105  IP_RO, 0, IPS_IDLE);
106 
107  IUFillSwitch(&FocusTelemetryS[0], "FOCUS_TELEMETRY_ON", "Enable", ISS_ON);
108  IUFillSwitch(&FocusTelemetryS[1], "FOCUS_TELEMETRY_OFF", "Disable", ISS_OFF);
109  IUFillSwitchVector(&FocusTelemetrySP, FocusTelemetryS, 2, getDeviceName(), "FOCUS_TELEMETRY", "Telemetry", "Operation",
110  IP_RW,
111  ISR_1OFMANY, 0, IPS_IDLE);
112 
113  // Mode parameters
114  IUFillNumber(&FocusModeAN[0], "FOCUS_SLOPE_A", "Slope A", "%.0f", -999, 999, 10, 0);
115  IUFillNumber(&FocusModeAN[1], "FOCUS_INTERCEPT_A", "Intercept A", "%.0f", 0, FocusAbsPosN[0].max, 10, 0);
116  IUFillNumber(&FocusModeAN[2], "FOCUS_DELAY_A", "Delay A", "%.2f", 0.00, 9.99, 1.0, 0);
117  IUFillNumberVector(&FocusModeANP, FocusModeAN, 3, getDeviceName(), "FOCUS_MODE_A", "Mode A", "Presets", IP_RW, 0, IPS_IDLE);
118  IUFillNumber(&FocusModeBN[0], "FOCUS_SLOPE_B", "Slope B", "%.0f", -999, 999, 10, 0);
119  IUFillNumber(&FocusModeBN[1], "FOCUS_INTERCEPT_B", "Intercept B", "%.0f", 0, FocusAbsPosN[0].max, 10, 0);
120  IUFillNumber(&FocusModeBN[2], "FOCUS_DELAY_B", "Delay B", "%.2f", 0.00, 9.99, 1.0, 0);
121  IUFillNumberVector(&FocusModeBNP, FocusModeBN, 3, getDeviceName(), "FOCUS_MODE_B", "Mode B", "Presets", IP_RW, 0, IPS_IDLE);
122 
123  IUFillSwitch(&FocusStartModeS[0], "FOCUS_START_ON", "Enable", ISS_OFF);
124  IUFillSwitch(&FocusStartModeS[1], "FOCUS_START_OFF", "Disable", ISS_ON);
125  IUFillSwitchVector(&FocusStartModeSP, FocusStartModeS, 2, getDeviceName(), "FOCUS_START_MODE", "Startup Mode", "Presets",
126  IP_RW,
127  ISR_1OFMANY, 0, IPS_IDLE);
128 
129  // Default to 19200
131 
132  addAuxControls();
133 
135 
136  return true;
137 }
138 
139 /****************************************************************
140 **
141 **
142 *****************************************************************/
144 {
145  //LOGF_DEBUG("%s %s",__FUNCTION__, me);
147 
148  if (isConnected())
149  {
150  defineProperty(&FocusGotoSP);
151  defineProperty(&FocusTemperatureNP);
152  defineProperty(&FocusPowerSP);
153  defineProperty(&FocusModeSP);
154  defineProperty(&FocusTelemetrySP);
155  defineProperty(&FocusStartModeSP);
156  defineProperty(&FocusModeANP);
157  defineProperty(&FocusModeBNP);;
158  GetFocusParams();
159  }
160  else
161  {
162  deleteProperty(FocusGotoSP.name);
163  deleteProperty(FocusTemperatureNP.name);
164  deleteProperty(FocusPowerSP.name);
165  deleteProperty(FocusModeSP.name);
166  deleteProperty(FocusTelemetrySP.name);
167  deleteProperty(FocusStartModeSP.name);
168  deleteProperty(FocusModeANP.name);
169  deleteProperty(FocusModeBNP.name);;
170  }
171 
172  return true;
173 }
174 
175 /****************************************************************
176 **
177 **
178 *****************************************************************/
179 bool TCFS::saveConfigItems(FILE *fp)
180 {
182 
183  IUSaveConfigNumber(fp, &FocusModeANP);
184  IUSaveConfigNumber(fp, &FocusModeBNP);
185  IUSaveConfigSwitch(fp, &FocusStartModeSP);
186 
187  // Add more properties to config file here
188  // IUSaveConfigSwitch(fp, &SwitchSP);
189  // IUSaveConfigNumber(fp, &NumberNP);
190  // IUSaveConfigText(fp, &TextTP);
191 
192  return true;
193 }
194 
195 /****************************************************************
196 **
197 **
198 *****************************************************************/
200 {
201  LOGF_DEBUG("A slope=%.0f", FocusModeANP.np[0].value);//, FocusModeAN[0].value);
202  /*
203  char response[TCFS_MAX_CMD] = { 0 };
204  int slope;
205  int is_negative;
206  dispatch_command(FRSLOP, 0, MODE_A);
207  read_tcfs(response);
208  if(sscanf(response, "A=%04d", &slope)<=0)
209  {
210  LOGF_WARN("Failed to read slope A from response: %s", response);
211  return;
212  }
213  response[0] = '\0';
214  dispatch_command(FRSIGN, 0, MODE_A);
215  read_tcfs(response);
216  if(sscanf(response, "A=%01d", &is_negative)<=0)
217  {
218  LOGF_WARN("Failed to read slope sign A from response: %s", response);
219  return;
220  }
221 
222  FocusModeANP.np[0].value = slope * (is_negative==1?-1:1);
223  IDSetNumber(&FocusModeANP, nullptr);
224 
225  response[0] = '\0';
226  dispatch_command(FRSLOP, 0, MODE_B);
227  read_tcfs(response);
228  if(sscanf(response, "B=%04d", &slope)<=0)
229  {
230  LOGF_WARN("Failed to read slope B from response: %s", response);
231  return;
232  }
233 
234  response[0] = '\0';
235  dispatch_command(FRSIGN, 0, MODE_B);
236  read_tcfs(response);
237  if(sscanf(response, "B=%01d", &is_negative)<=0)
238  {
239  LOGF_WARN("Failed to read slope sign B from response: %s", response);
240  return;
241  }
242 
243  FocusModeBNP.np[0].value = slope * (is_negative==1?-1:1);
244  IDSetNumber(&FocusModeBNP, nullptr);
245  */
246 }
247 
248 /****************************************************************
249 **
250 **
251 *****************************************************************/
253 {
254  LOGF_DEBUG("%s %s", __FUNCTION__, me);
255  if (isSimulation())
256  {
257  LOG_INFO("TCF-S: Simulating connection.");
258  currentPosition = simulated_position;
259  return true;
260  }
261  char response[TCFS_MAX_CMD] = { 0 };
262  dispatch_command(FWAKUP);
263  read_tcfs(response);
264  if (strcmp(response, "WAKE") == 0)
265  {
266  LOG_INFO("TCF-S Focuser is awake");
267  tcflush(PortFD, TCIOFLUSH);
268  }
269 
270  if(SetManualMode())
271  {
272  LOG_INFO("Successfully connected to TCF-S Focuser in Manual Mode.");
273 
274  // Enable temperature readout
275  FocusTemperatureNP.s = IPS_OK;
276 
277  return true;
278  }
279  tcflush(PortFD, TCIOFLUSH);
280  LOG_ERROR("Failed connection to TCF-S Focuser.");
281  return false;
282 }
283 /****************************************************************
284 **
285 **
286 *****************************************************************/
288 {
289  char response[TCFS_MAX_CMD] = { 0 };
290  for(int retry = 0; retry < 5; retry++)
291  {
292  dispatch_command(FMMODE);
293  read_tcfs(response);
294  if (strcmp(response, "!") == 0)
295  {
296  tcflush(PortFD, TCIOFLUSH);
297  currentMode = MANUAL;
298  return true;
299  }
300  }
301  tcflush(PortFD, TCIOFLUSH);
302  return false;
303 }
304 
305 /****************************************************************
306 **
307 **
308 *****************************************************************/
310 {
311  FocusTemperatureNP.s = IPS_IDLE;
312  IDSetNumber(&FocusTemperatureNP, nullptr);
313 
314  dispatch_command(FFMODE);
315 
316  return INDI::Focuser::Disconnect();
317 }
318 
319 /****************************************************************
320 **
321 **
322 *****************************************************************/
323 bool TCFS::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
324 {
325  //LOGF_DEBUG("%s %s %s %s",__FUNCTION__, me, dev, name);
326  // first check if it's for our device
327  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
328  {
329  char response[TCFS_MAX_CMD] = { 0 };
330  // In Auto mode only FMMODE can be accepted
331  // In Sleep mode only FWAKUP can be accepted
332  // While focuser is moving don't allow actions other than FMMODE
333 
334  if (!strcmp(name, FocusModeANP.name))
335  {
336  IUUpdateNumber(&FocusModeANP, values, names, n);
337 
338  dispatch_command(FLSLOP, FocusModeAN[0].value, MODE_A);
339  if (read_tcfs(response) == false)
340  {
341  FocusModeANP.s = IPS_ALERT;
342  IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
343  return true;
344  }
345  dispatch_command(FLSIGN, FocusModeAN[0].value, MODE_A);
346  if (read_tcfs(response) == false)
347  {
348  FocusModeANP.s = IPS_ALERT;
349  IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
350  return true;
351  }
352  //saveConfig();
353  dispatch_command(FDELAY, FocusModeAN[2].value * 100, MODE_A);
354  if (read_tcfs(response) == false)
355  {
356  FocusModeANP.s = IPS_ALERT;
357  IDSetNumber(&FocusModeANP, "Error reading TCF-S reply.");
358  return true;
359  }
360  //saveConfig();
361  FocusModeANP.s = IPS_OK;
362  IDSetNumber(&FocusModeANP, nullptr);
363 
364  return true;
365  }
366  if (!strcmp(name, FocusModeBNP.name))
367  {
368  IUUpdateNumber(&FocusModeBNP, values, names, n);
369 
370  dispatch_command(FLSLOP, FocusModeBN[0].value, MODE_B);
371  if (read_tcfs(response) == false)
372  {
373  FocusModeBNP.s = IPS_ALERT;
374  IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
375  return true;
376  }
377  dispatch_command(FLSIGN, FocusModeBN[0].value, MODE_B);
378  if (read_tcfs(response) == false)
379  {
380  FocusModeBNP.s = IPS_ALERT;
381  IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
382  return true;
383  }
384  dispatch_command(FDELAY, FocusModeBN[2].value * 100, MODE_B);
385  if (read_tcfs(response) == false)
386  {
387  FocusModeBNP.s = IPS_ALERT;
388  IDSetNumber(&FocusModeBNP, "Error reading TCF-S reply.");
389  return true;
390  }
391  //saveConfig();
392  FocusModeBNP.s = IPS_OK;
393  IDSetNumber(&FocusModeBNP, nullptr);
394 
395  return true;
396  }
397  }
398 
399  return Focuser::ISNewNumber(dev, name, values, names, n);
400 }
401 
402 /****************************************************************
403 **
404 **
405 *****************************************************************/
406 bool TCFS::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
407 {
408  //LOGF_DEBUG("%s %s %s %s",__FUNCTION__, me, dev, name);
409  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
410  {
411  char response[TCFS_MAX_CMD] = { 0 };
412  // In Auto mode only FMMODE can be accepted
413  // In Sleep mode only FWAKUP can be accepted
414  // While focuser is moving don't allow actions other than FMMODE
415  if (!strcmp(FocusMotionSP.name, name))
416  {
417  if (FocusModeSP.sp[0].s != ISS_ON)
418  {
419  LOG_WARN("The focuser can only be moved in Manual mode.");
420  return true;
421  }
422  }
423  if (FocusRelPosNP.s == IPS_BUSY)
424  {
425  LOG_WARN("The focuser is in motion. Wait until it has stopped");
426  return true;
427  }
428  if (!strcmp(FocusPowerSP.name, name))
429  {
430  IUUpdateSwitch(&FocusPowerSP, states, names, n);
431  bool sleep = false;
432 
433  ISwitch *sp = IUFindOnSwitch(&FocusPowerSP);
434 
435  // Sleep
436  if (!strcmp(sp->name, "FOCUS_SLEEP"))
437  {
438  dispatch_command(FSLEEP);
439  sleep = true;
440  }
441  // Wake Up
442  else
443  dispatch_command(FWAKUP);
444 
445  if (read_tcfs(response) == false)
446  {
447  IUResetSwitch(&FocusPowerSP);
448  FocusPowerSP.s = IPS_ALERT;
449  IDSetSwitch(&FocusPowerSP, "Error reading TCF-S reply.");
450  return true;
451  }
452 
453  if (sleep)
454  {
455  if (isSimulation())
456  strncpy(response, "ZZZ", TCFS_MAX_CMD);
457 
458  if (strcmp(response, "ZZZ") == 0)
459  {
460  FocusPowerSP.s = IPS_OK;
461  IDSetSwitch(&FocusPowerSP, "Focuser is set into sleep mode.");
463  IDSetNumber(&FocusAbsPosNP, nullptr);
464  // if (FocusTemperatureNP)
465  {
466  FocusTemperatureNP.s = IPS_IDLE;
467  IDSetNumber(&FocusTemperatureNP, nullptr);
468  }
469 
470  return true;
471  }
472  else
473  {
474  FocusPowerSP.s = IPS_ALERT;
475  IDSetSwitch(&FocusPowerSP, "Focuser sleep mode operation failed. Response: %s.", response);
476  return true;
477  }
478  }
479  else
480  {
481  if (isSimulation())
482  strncpy(response, "WAKE", TCFS_MAX_CMD);
483 
484  if (strcmp(response, "WAKE") == 0)
485  {
486  FocusPowerSP.s = IPS_OK;
487  IDSetSwitch(&FocusPowerSP, "Focuser is awake.");
489  IDSetNumber(&FocusAbsPosNP, nullptr);
490  // if (FocusTemperatureNP)
491  {
492  FocusTemperatureNP.s = IPS_OK;
493  IDSetNumber(&FocusTemperatureNP, nullptr);
494  }
495 
496  return true;
497  }
498  else
499  {
500  FocusPowerSP.s = IPS_ALERT;
501  IDSetSwitch(&FocusPowerSP, "Focuser wake up operation failed. Response: %s", response);
502  return true;
503  }
504  }
505  }
506 
507  // Do not process any command if focuser is asleep
508  if (isConnected() && FocusPowerSP.sp[0].s == ISS_ON)
509  {
510  auto svp = getSwitch(name);
511  if (svp)
512  {
513  svp.setState(IPS_IDLE);
514  LOG_WARN("Focuser is still in sleep mode. Wake up in order to issue commands.");
515  svp.apply();
516  }
517  return true;
518  }
519 
520  if (!strcmp(FocusModeSP.name, name))
521  {
522  IUUpdateSwitch(&FocusModeSP, states, names, n);
523  FocusModeSP.s = IPS_OK;
524 
525  ISwitch *sp = IUFindOnSwitch(&FocusModeSP);
526 
527  if (!strcmp(sp->name, "Manual"))
528  {
529  if (!isSimulation() && !SetManualMode())
530  {
531  IUResetSwitch(&FocusModeSP);
532  FocusModeSP.s = IPS_ALERT;
533  IDSetSwitch(&FocusModeSP, "Error switching to manual mode. No reply from TCF-S. Try again.");
534  return true;
535  }
536  LOG_INFO("Entered Manual Mode");
537  currentMode = MANUAL;
538  }
539  else if (!strcmp(sp->name, "Auto A"))
540  {
541  if(FocusStartModeSP.sp[0].s == ISS_ON)
542  {
543  FocusModeSP.s = IPS_BUSY;
544  uint32_t startPos = -FocusTemperatureN[0].value * FocusModeAN[0].value
545  + FocusModeAN[1].value;
546  LOGF_DEBUG("Autocomp A T=%.1f; m=%f; i=%f; p0=%d;",
547  FocusTemperatureN[0].value,
548  FocusModeAN[0].value,
549  FocusModeAN[1].value,
550  startPos);
551  MoveAbsFocuser(startPos);
552  }
553  else
554  {
555  dispatch_command(FAMODE);
556  read_tcfs(response);
557  if (!isSimulation() && strcmp(response, "A") != 0)
558  {
559  IUResetSwitch(&FocusModeSP);
560  FocusModeSP.s = IPS_ALERT;
561  IDSetSwitch(&FocusModeSP, "Error switching to Auto Mode A, No reply from TCF-S. Try again.");
562  }
563  LOG_INFO("Entered Auto Mode A");
564  currentMode = MODE_A;
565  }
566  }
567  else
568  {
569  if(FocusStartModeSP.sp[0].s == ISS_ON)
570  {
571  FocusModeSP.s = IPS_BUSY;
572  uint32_t startPos = -FocusTemperatureN[0].value * FocusModeBN[0].value
573  + FocusModeBN[1].value;
574  LOGF_DEBUG("Autocomp B T=%.1f; m=%f; i=%f; p0=%d;",
575  FocusTemperatureN[0].value,
576  FocusModeBN[0].value,
577  FocusModeBN[1].value,
578  startPos);
579  MoveAbsFocuser(startPos);
580  }
581  else
582  {
583  dispatch_command(FBMODE);
584  read_tcfs(response);
585  if (!isSimulation() && strcmp(response, "B") != 0)
586  {
587  IUResetSwitch(&FocusModeSP);
588  FocusModeSP.s = IPS_ALERT;
589  IDSetSwitch(&FocusModeSP, "Error switching to Auto Mode B, No reply from TCF-S. Try again.");
590  }
591  LOG_INFO("Entered Auto Mode B");
592  currentMode = MODE_B;
593  }
594  }
595 
596  IDSetSwitch(&FocusModeSP, nullptr);
597  return true;
598  }
599  // Do not process any other command if focuser is in auto mode
600  if (isConnected() && FocusModeSP.sp[0].s != ISS_ON)
601  {
602  auto svp = getSwitch(name);
603  if (svp)
604  {
605  svp.setState(IPS_IDLE);
606  LOG_WARN("Focuser is in auto mode. Change to manual in order to issue commands.");
607  svp.apply();
608  }
609  return true;
610  }
611 
612  if (!strcmp(FocusStartModeSP.name, name))
613  {
614  IUUpdateSwitch(&FocusStartModeSP, states, names, n);
615  FocusStartModeSP.s = IPS_OK;
616  // ISwitch *sp = IUFindOnSwitch(&FocusStartModeSP);
617  IDSetSwitch(&FocusStartModeSP, nullptr);
618  LOGF_DEBUG("Start Mode %d", FocusStartModeSP.sp[0].s );
619  return true;
620  }
621 
622  if (!strcmp(FocusGotoSP.name, name))
623  {
624  if (FocusModeSP.sp[0].s != ISS_ON)
625  {
626  FocusGotoSP.s = IPS_IDLE;
627  IDSetSwitch(&FocusGotoSP, nullptr);
628  LOG_WARN("The focuser can only be moved in Manual mode.");
629  return false;
630  }
631 
632  IUUpdateSwitch(&FocusGotoSP, states, names, n);
633  FocusGotoSP.s = IPS_BUSY;
634 
635  ISwitch *sp = IUFindOnSwitch(&FocusGotoSP);
636 
637  // Min
638  if (!strcmp(sp->name, "FOCUS_MIN"))
639  {
640  targetTicks = currentPosition;
642  IDSetSwitch(&FocusGotoSP, "Moving focuser to minimum position...");
643  }
644  // Center
645  else if (!strcmp(sp->name, "FOCUS_CENTER"))
646  {
647  dispatch_command(FCENTR);
650  IDSetNumber(&FocusAbsPosNP, nullptr);
651  IDSetNumber(&FocusRelPosNP, nullptr);
652  IDSetSwitch(&FocusGotoSP, "Moving focuser to center position %d...", isTCFS3 ? 5000 : 3500);
653  return true;
654  }
655  // Max
656  else if (!strcmp(sp->name, "FOCUS_MAX"))
657  {
658  unsigned int delta = 0;
659  delta = FocusAbsPosN[0].max - currentPosition;
661  IDSetSwitch(&FocusGotoSP, "Moving focuser to maximum position %g...", FocusAbsPosN[0].max);
662  }
663  // Home
664  else if (!strcmp(sp->name, "FOCUS_HOME"))
665  {
666  dispatch_command(FHOME);
667  read_tcfs(response);
668 
669  if (isSimulation())
670  strncpy(response, "DONE", TCFS_MAX_CMD);
671 
672  if (strcmp(response, "DONE") == 0)
673  {
674  IUResetSwitch(&FocusGotoSP);
675  FocusGotoSP.s = IPS_OK;
676  IDSetSwitch(&FocusGotoSP, "Moving focuser to new calculated position based on temperature...");
677  return true;
678  }
679  else
680  {
681  IUResetSwitch(&FocusGotoSP);
682  FocusGotoSP.s = IPS_ALERT;
683  IDSetSwitch(&FocusGotoSP, "Failed to move focuser to home position!");
684  return true;
685  }
686  }
687 
688  IDSetSwitch(&FocusGotoSP, nullptr);
689  return true;
690  }
691  // handle quiet mode on/off
692  if (!strcmp(FocusTelemetrySP.name, name))
693  {
694  IUUpdateSwitch(&FocusTelemetrySP, states, names, n);
695 
696 
697  bool quiet = false;
698 
699  ISwitch *sp = IUFindOnSwitch(&FocusTelemetrySP);
700 
701  // Telemetry off
702  if (!strcmp(sp->name, "FOCUS_TELEMETRY_OFF"))
703  {
704  dispatch_command(FQUIET, 1);
705  quiet = true;
706  }
707  // Telemetry On
708  else
709  dispatch_command(FQUIET, 0);
710 
711  if (read_tcfs(response) == false)
712  {
713  IUResetSwitch(&FocusTelemetrySP);
714  FocusTelemetrySP.s = IPS_ALERT;
715  IDSetSwitch(&FocusTelemetrySP, "Error reading TCF-S reply.");
716  return true;
717  }
718 
719  if (isSimulation())
720  strncpy(response, "DONE", TCFS_MAX_CMD);
721 
722  if (strcmp(response, "DONE") == 0)
723  {
724  FocusTelemetrySP.s = IPS_OK;
725  IDSetSwitch(&FocusTelemetrySP,
726  quiet ? "Focuser Telemetry is off." : "Focuser Telemetry is on.");
727  // if (FocusTemperatureNP)
728  {
729  FocusTemperatureNP.s = quiet ? IPS_IDLE : IPS_OK;
730  IDSetNumber(&FocusTemperatureNP, nullptr);
731  }
732  return true;
733  }
734  else
735  {
736  FocusTelemetrySP.s = IPS_ALERT;
737  IDSetSwitch(&FocusTelemetrySP, "Focuser telemetry mode failed. Response: %s.", response);
738  return true;
739  }
740  }
741  }
742  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
743 }
744 
745 IPState TCFS::MoveAbsFocuser(uint32_t targetTicks)
746 {
747  int delta = targetTicks - currentPosition;
748  LOGF_DEBUG("Moving to absolute position %d using offset %d", targetTicks, delta);
749  return MoveRelFocuser(delta < 0 ? FOCUS_INWARD : FOCUS_OUTWARD, std::abs(delta));
750 }
751 
753 {
754  // if (FocusModeSP.sp[0].s != ISS_ON)
755  // {
756  // LOG_WARN("The focuser can only be moved in Manual mode.");
757  // return IPS_ALERT;
758  // }
759  // The TCFS does not allow any commands othern than FMMODE whilst it is
760  // in auto mode. But this then prevents auto setting of filter offsets during
761  // an imaging sequence. So switch to manual mode, apply the offset then return
762  // to auto mode.
763  targetTicks = ticks;
764  targetPosition = currentPosition;
765 
766  TCFSMode prevMode = currentMode;
767  if(currentMode != MANUAL)
768  {
769  SetManualMode();
770  }
771  // Inward
772  if (dir == FOCUS_INWARD)
773  {
774  targetPosition -= targetTicks;
775  dispatch_command(FIN);
776 
777  LOGF_DEBUG("Moving inward by %d steps to position %d", targetTicks, targetPosition);
778  }
779  // Outward
780  else
781  {
782  targetPosition += targetTicks;
783  dispatch_command(FOUT);
784 
785  LOGF_DEBUG("Moving outward by %d steps to position %d", targetTicks, targetPosition);
786  }
787 
790  IDSetNumber(&FocusAbsPosNP, nullptr);
791  IDSetNumber(&FocusRelPosNP, nullptr);
792 
793  simulated_position = targetPosition;
794  if(prevMode != MANUAL)
795  {
796  IUResetSwitch(&FocusModeSP);
797  if (prevMode == MODE_A)
798  {
799  FocusModeSP.sp[1].s = ISS_ON;
800  }
801  else
802  {
803  FocusModeSP.sp[2].s = ISS_ON;
804  }
805  FocusModeSP.s = IPS_BUSY;
806  IDSetSwitch(&FocusModeSP, nullptr);
807  }
808 
809  return IPS_BUSY;
810 }
811 
812 bool TCFS::dispatch_command(TCFSCommand command_type, int val, TCFSMode m)
813 {
814  int err_code = 0, nbytes_written = 0;
815  char command[TCFS_MAX_CMD] = {0};
816 
817  switch (command_type)
818  {
819  // Focuser Manual Mode
820  case FMMODE:
821  strncpy(command, "FMMODE", TCFS_MAX_CMD);
822  break;
823 
824  // Focuser Free Mode
825  case FFMODE:
826  strncpy(command, "FFMODE", TCFS_MAX_CMD);
827  break;
828  // Focuser Auto-A Mode
829  case FAMODE:
830  strncpy(command, "FAMODE", TCFS_MAX_CMD);
831  break;
832 
833  // Focuser Auto-B Mode
834  case FBMODE:
835  strncpy(command, "FBMODE", TCFS_MAX_CMD);
836  break;
837 
838  // Focus Center
839  case FCENTR:
840  strncpy(command, "FCENTR", TCFS_MAX_CMD);
841  break;
842 
843  // Focuser In “nnnn”
844  case FIN:
845  simulated_position = currentPosition;
846 
847  snprintf(command, TCFS_MAX_CMD, "FI%04u", targetTicks);
848  break;
849 
850  // Focuser Out “nnnn”
851  case FOUT:
852  simulated_position = currentPosition;
853 
854  snprintf(command, TCFS_MAX_CMD, "FO%04u", targetTicks);
855  break;
856 
857  // Focuser Position Read Out
858  case FPOSRO:
859  strncpy(command, "FPOSRO", TCFS_MAX_CMD);
860  break;
861 
862  // Focuser Temperature
863  case FTMPRO:
864  strncpy(command, "FTMPRO", TCFS_MAX_CMD);
865  break;
866 
867  // Focuser Sleep
868  case FSLEEP:
869  strncpy(command, "FSLEEP", TCFS_MAX_CMD);
870  break;
871  // Focuser Wake Up
872  case FWAKUP:
873  strncpy(command, "FWAKUP", TCFS_MAX_CMD);
874  break;
875  // Focuser Home Command
876  case FHOME:
877  strncpy(command, "FHOME", TCFS_MAX_CMD);
878  break;
879  // Focuser Quiet Command
880  case FQUIET:
881  snprintf(command, TCFS_MAX_CMD, "FQUIT%01d", val);
882  break;
883  // Focuser Load Slope Command
884  case FLSLOP:
885  snprintf(command, TCFS_MAX_CMD, "FL%c%03d", m == MODE_A ? 'A' : 'B', abs(val));
886  break;
887  // Focuser Load Delay Command
888  case FDELAY:
889  snprintf(command, TCFS_MAX_CMD, "FD%c%03d", m == MODE_A ? 'A' : 'B', val);
890  break;
891  // Focuser Load Sign Command
892  case FLSIGN:
893  snprintf(command, TCFS_MAX_CMD, "FZ%cxx%01d", m == MODE_A ? 'A' : 'B', val >= 0 ? 0 : 1);
894  break;
895  // Focuser Read Slope Command
896  case FRSLOP:
897  snprintf(command, TCFS_MAX_CMD, "FREAD%c", m == MODE_A ? 'A' : 'B');
898  break;
899  // Focuser Read Sign Command
900  case FRSIGN:
901  snprintf(command, TCFS_MAX_CMD, "Ftxxx%c", m == MODE_A ? 'A' : 'B');
902  break;
903  case FFWVER:
904  snprintf(command, TCFS_MAX_CMD, "FVxxxx");
905  break;
906  }
907 
908  LOGF_DEBUG("CMD <%s>", command);
909 
910  if (isSimulation())
911  return true;
912 
913  tcflush(PortFD, TCIOFLUSH);
914 
915  if ( (err_code = tty_write(PortFD, command, strlen(command), &nbytes_written)) != TTY_OK)
916  {
917  char tcfs_error[TCFS_ERROR_BUFFER];
918  tty_error_msg(err_code, tcfs_error, TCFS_ERROR_BUFFER);
919  LOGF_ERROR("TTY error detected: %s", tcfs_error);
920  return false;
921  }
922 
923  return true;
924 }
925 
927 {
928  static double lastPosition = -1, lastTemperature = -1000;
929 
930  if (!isConnected())
931  {
933  return;
934  }
935 
936  char response[TCFS_MAX_CMD] = { 0 };
937  // If focuser is moving wait until "*" is received
938  // Then set moving indicator to OK
939  if (FocusRelPosNP.s == IPS_BUSY)
940  {
941  LOGF_DEBUG("%s Motion in Progress...", __FUNCTION__);
942  if (read_tcfs(response, true) == false)
943  {
945  return;
946  }
947  LOGF_DEBUG("%s READY %s", __FUNCTION__, response );
948  if(strcmp(response, "*") == 0)
949  {
952  IDSetNumber(&FocusAbsPosNP, nullptr);
953  IDSetNumber(&FocusRelPosNP, nullptr);
954 
955  // If the focuser has stopped moving and auto mode is requested then
956  // it is ok to set it now
957  if(FocusModeSP.s == IPS_BUSY && // Had to move before going Auto
958  (FocusModeSP.sp[1].s == ISS_ON || FocusModeSP.sp[2].s == ISS_ON))
959  {
960  const char* mode = (FocusModeSP.sp[1].s == ISS_ON) ? "A" : "B";
961  dispatch_command(
962  (FocusModeSP.sp[1].s == ISS_ON) ? FAMODE : FBMODE);
963  read_tcfs(response);
964  if (!isSimulation() && strcmp(response, mode) != 0)
965  {
966  IUResetSwitch(&FocusModeSP);
967  FocusModeSP.s = IPS_ALERT;
968  IDSetSwitch(&FocusModeSP, "Error switching to Auto Mode %s. No reply from TCF-S. Try again.", mode);
970  return;
971  }
972  FocusModeSP.s = IPS_OK;
973  LOGF_INFO("Entered Auto Mode %s", mode);
974  currentMode = (FocusModeSP.sp[1].s == ISS_ON) ? MODE_A : MODE_B;
975  IDSetSwitch(&FocusModeSP, nullptr);
976  }
978  return;
979  }
980  }
981 
982  int f_position = 0;
983  float f_temperature = 0;
984 
985  if(!isSimulation() && currentMode != MANUAL)
986  {
987  if (FocusTelemetrySP.sp[1].s == ISS_ON)
988  {
989  LOGF_DEBUG("%s %s", __FUNCTION__, "Telemetry is off");
991  return;
992  }
993  for(int i = 0; i < 2; i++)
994  {
995  if (read_tcfs(response, true) == false)
996  {
998  return;
999  }
1000  LOGF_DEBUG("%s Received %s", __FUNCTION__, response);
1001  if(sscanf(response, "P=%d", &f_position) == 1)
1002  {
1003  currentPosition = f_position;
1004  if (lastPosition != currentPosition)
1005  {
1006  lastPosition = currentPosition;
1007  IDSetNumber(&FocusAbsPosNP, nullptr);
1008  }
1009  }
1010  else if(sscanf(response, "T=%f", &f_temperature) == 1)
1011  {
1012  FocusTemperatureNP.np[0].value = f_temperature;
1013 
1014  if (lastTemperature != FocusTemperatureNP.np[0].value)
1015  {
1016  lastTemperature = FocusTemperatureNP.np[0].value;
1017  IDSetNumber(&FocusTemperatureNP, nullptr);
1018  }
1019  }
1020  }
1022  return;
1023  }
1024 
1025  if (FocusGotoSP.s == IPS_BUSY)
1026  {
1027  ISwitch *sp = IUFindOnSwitch(&FocusGotoSP);
1028 
1029  if (sp != nullptr && strcmp(sp->name, "FOCUS_CENTER") == 0)
1030  {
1031  bool rc = read_tcfs(response, true);
1032 
1033  if (!rc)
1034  {
1036  return;
1037  }
1038 
1039  if (isSimulation())
1040  strncpy(response, "CENTER", TCFS_MAX_CMD);
1041 
1042  if (strcmp(response, "CENTER") == 0)
1043  {
1044  IUResetSwitch(&FocusGotoSP);
1045  FocusGotoSP.s = IPS_OK;
1047 
1048  IDSetSwitch(&FocusGotoSP, nullptr);
1049  IDSetNumber(&FocusAbsPosNP, nullptr);
1050 
1051  LOG_INFO("Focuser moved to center position.");
1052  }
1053  }
1054  }
1055 
1056  switch (FocusAbsPosNP.s)
1057  {
1058  case IPS_OK:
1059  if (FocusModeSP.sp[0].s == ISS_ON)
1060  dispatch_command(FPOSRO);
1061 
1062  if (read_tcfs(response) == false)
1063  {
1065  return;
1066  }
1067 
1068  if (isSimulation())
1069  snprintf(response, TCFS_MAX_CMD, "P=%04d", (int)simulated_position);
1070 
1071  sscanf(response, "P=%d", &f_position);
1072  currentPosition = f_position;
1073 
1074  if (lastPosition != currentPosition)
1075  {
1076  lastPosition = currentPosition;
1077  IDSetNumber(&FocusAbsPosNP, nullptr);
1078  }
1079  break;
1080 
1081  case IPS_BUSY:
1082  if (read_tcfs(response, true) == false)
1083  {
1085  return;
1086  }
1087 
1088  // Ignore error
1089  if (strstr(response, "ER") != nullptr)
1090  {
1091  LOGF_DEBUG("Received error: %s", response);
1093  return;
1094  }
1095 
1096  if (isSimulation())
1097  strncpy(response, "*", 2);
1098 
1099  if (strcmp(response, "*") == 0)
1100  {
1101  LOGF_DEBUG("Moving focuser %d steps to position %d.", targetTicks, targetPosition);
1104  FocusGotoSP.s = IPS_OK;
1105  IDSetNumber(&FocusAbsPosNP, nullptr);
1106  IDSetNumber(&FocusRelPosNP, nullptr);
1107  IDSetSwitch(&FocusGotoSP, nullptr);
1108  }
1109  else
1110  {
1112  LOGF_ERROR("Unable to read response from focuser #%s#.", response);
1113  IDSetNumber(&FocusAbsPosNP, nullptr);
1114  }
1115  break;
1116 
1117  default:
1118  break;
1119  }
1120 
1121  if (FocusTemperatureNP.s == IPS_OK || FocusTemperatureNP.s == IPS_BUSY)
1122  {
1123  // Read Temperature
1124  // Manual Mode
1125  if (FocusModeSP.sp[0].s == ISS_ON)
1126  dispatch_command(FTMPRO);
1127 
1128  if (read_tcfs(response) == false)
1129  {
1130  FocusTemperatureNP.s = IPS_ALERT;
1131  IDSetNumber(&FocusTemperatureNP, nullptr);
1132  LOG_ERROR("Failed to read temperature. Is sensor connected?");
1133 
1135  return;
1136  }
1137 
1138  if (isSimulation())
1139  snprintf(response, TCFS_MAX_CMD, "T=%0.1f", simulated_temperature);
1140 
1141  int rc = sscanf(response, "T=%f", &f_temperature);
1142 
1143  if (rc == 1)
1144  {
1145  FocusTemperatureNP.np[0].value = f_temperature;
1146 
1147  if (fabs(lastTemperature - FocusTemperatureNP.np[0].value) > 0.01)
1148  {
1149  lastTemperature = FocusTemperatureNP.np[0].value;
1150  IDSetNumber(&FocusTemperatureNP, nullptr);
1151  }
1152  }
1153  else
1154  {
1155  FocusTemperatureNP.s = IPS_ALERT;
1156  LOGF_ERROR("Failed to read temperature: %s", response);
1157  IDSetNumber(&FocusTemperatureNP, nullptr);
1158  }
1159  }
1160 
1162 }
1163 
1164 bool TCFS::read_tcfs(char *response, bool silent)
1165 {
1166  int err_code = 0, nbytes_read = 0;
1167 
1168  if (isSimulation())
1169  {
1170  strncpy(response, "SIMULATION", TCFS_MAX_CMD);
1171  return true;
1172  }
1173 
1174  // Read until encountring a CR
1175  if ((err_code = tty_read_section(PortFD, response, 0x0D, 2, &nbytes_read)) != TTY_OK)
1176  {
1177  if (!silent)
1178  {
1179  char err_msg[TCFS_ERROR_BUFFER];
1180  tty_error_msg(err_code, err_msg, 32);
1181  LOGF_ERROR("TTY error detected: %s", err_msg);
1182  }
1183 
1184  return false;
1185  }
1186 
1187  // Remove LF & CR
1188  response[nbytes_read - 2] = '\0';
1189 
1190  tcflush(PortFD, TCIOFLUSH);
1191 
1192  if (strstr(response, "ER="))
1193  {
1194  int errorCode = 0;
1195  sscanf(response, "ER=%d", &errorCode);
1196  LOGF_ERROR("Error Code <%d>", errorCode);
1197  return false;
1198  }
1199 
1200  LOGF_DEBUG("RES <%s>", response);
1201  return true;
1202 }
1203 
1205 {
1206  return mydev;
1207 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
INDI::PropertySwitch getSwitch(const char *name) const
Definition: basedevice.cpp:99
virtual bool Disconnect()
Disconnect from device.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
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.
ISwitchVectorProperty FocusMotionSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
Connection::Serial * serialConnection
Definition: indifocuser.h:116
Definition: tcfs.h:32
void GetFocusParams()
Definition: tcfs.cpp:199
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
Definition: tcfs.cpp:179
TCFS()
Definition: tcfs.cpp:42
@ FDELAY
Definition: tcfs.h:51
@ FQUIET
Definition: tcfs.h:50
@ FPOSRO
Definition: tcfs.h:43
@ FWAKUP
Definition: tcfs.h:46
@ FBMODE
Definition: tcfs.h:39
@ FMMODE
Definition: tcfs.h:36
@ FAMODE
Definition: tcfs.h:38
@ FFWVER
Definition: tcfs.h:54
@ FOUT
Definition: tcfs.h:42
@ FHOME
Definition: tcfs.h:47
@ FLSIGN
Definition: tcfs.h:53
@ FTMPRO
Definition: tcfs.h:44
@ FFMODE
Definition: tcfs.h:37
@ FSLEEP
Definition: tcfs.h:45
@ FRSLOP
Definition: tcfs.h:48
@ FRSIGN
Definition: tcfs.h:52
@ FLSLOP
Definition: tcfs.h:49
@ FCENTR
Definition: tcfs.h:40
@ FIN
Definition: tcfs.h:41
virtual bool Handshake() override
perform handshake with device to check communication
Definition: tcfs.cpp:252
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: tcfs.cpp:54
const char * getDefaultName() override
Definition: tcfs.cpp:1204
bool SetManualMode()
Definition: tcfs.cpp:287
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: tcfs.cpp:752
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: tcfs.cpp:926
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: tcfs.cpp:323
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: tcfs.cpp:143
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: tcfs.cpp:406
virtual bool Disconnect() override
Disconnect from device.
Definition: tcfs.cpp:309
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: tcfs.cpp:745
TCFSMode
Definition: tcfs.h:58
@ MANUAL
Definition: tcfs.h:59
@ MODE_B
Definition: tcfs.h:61
@ MODE_A
Definition: tcfs.h:60
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
double max(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_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(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition: indidevapi.c:108
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidevapi.c:158
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
char * me
Definition: indidriver.c:50
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#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
One switch descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
#define currentPosition
Definition: tcfs.cpp:33
#define mydev
Definition: tcfs.cpp:32
#define TCFS_MAX_CMD
Definition: tcfs.h:28
#define TCFS_ERROR_BUFFER
Definition: tcfs.h:29