Instrument Neutral Distributed Interface INDI  2.0.2
ifwoptec.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2016 Philippe Besson. All rights reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "ifwoptec.h"
20 
21 #include "indicom.h"
22 #include "indicontroller.h"
23 //#include "connectionplugins/connectioninterface.h"
25 
26 #include <memory>
27 #include <regex>
28 #include <cstring>
29 #include <unistd.h>
30 
31 std::unique_ptr<FilterIFW> filter_ifw(new FilterIFW());
32 
33 /************************************************************************************
34 *
35 ************************************************************************************/
37 {
38  //ctor
40  strncpy(filterSim, filterSim5, sizeof(filterSim)); // For simulation mode
41 
42  // Set communication to serail only and avoid driver crash at starting up
43  // setFilterConnection(CONNECTION_SERIAL);
45 
46  // We add an additional debug level so we can log verbose member function starting
47  // DBG_TAG is used by macro DEBUGTAG() define in ifwoptec.h
48  INDI::Logger::getInstance().addDebugLevel("Function tag", "Tag");
49 }
50 
51 /************************************************************************************
52 *
53 ************************************************************************************/
55 {
56  return "Optec IFW";
57 }
58 
59 /**************************************************************************************
60 *
61 ***************************************************************************************/
63 {
65 
66  // Settings
67  IUFillText(&WheelIDT[0], "ID", "ID", "-");
68  IUFillTextVector(&WheelIDTP, WheelIDT, 1, getDeviceName(), "WHEEL_ID", "Wheel", FILTER_TAB, IP_RO, 60, IPS_IDLE);
69 
70  // Command
71  IUFillSwitch(&HomeS[0], "HOME", "Home", ISS_OFF);
73  IPS_IDLE);
74 
75  // Within simulation mode, provide possibilities to select the kind of filter wheel: 5 or 8 filters
76  IUFillSwitch(&FilterNbrS[0], "VAL5", "5", ISS_ON);
77  IUFillSwitch(&FilterNbrS[1], "VAL6", "6", ISS_OFF);
78  IUFillSwitch(&FilterNbrS[2], "VAL8", "8", ISS_OFF);
79  IUFillSwitch(&FilterNbrS[3], "VAL9", "9", ISS_OFF);
80  IUFillSwitchVector(&FilterNbrSP, FilterNbrS, 4, getDeviceName(), "FILTER_NBR", "Filter nbr", FILTER_TAB, IP_RW,
81  ISR_1OFMANY, 0, IPS_IDLE);
82 
83  // User could choice to unrestrict chars set to set the filternames if he accepts to have crazy display name on IFW box
84  // Within simulation mode, provide possibilities to select the kind of filter wheel: 5 or 8 filters
85  IUFillSwitch(&CharSetS[0], "RES", "Restricted", ISS_ON);
86  IUFillSwitch(&CharSetS[1], "UNRES", "All", ISS_OFF);
87  IUFillSwitchVector(&CharSetSP, CharSetS, 2, getDeviceName(), "CHARSET", "Chars allowed", FILTER_TAB, IP_RW,
88  ISR_1OFMANY, 0, IPS_IDLE);
89 
90  // Firmware of the IFW
91  IUFillText(&FirmwareT[0], "FIRMWARE", "Firmware", "Unknown");
92  IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "FIRMWARE_ID", "IFW", FILTER_TAB, IP_RO, 60, IPS_IDLE);
93 
94 
97 
98  return true;
99 }
100 
101 /************************************************************************************
102 *
103 ************************************************************************************/
105 {
107  if (isConnected())
108  {
111  defineProperty(&WheelIDTP); // ID of the wheel first in Filter tab page
112  // Then the button only for Simulation to select the number of filter of the Wheel (5 or 8)
113  if (isSimulation())
118 
119  GetFirmware(); // Try to get Firmware version of the IFW. NOt all Firmware support this function
120  moveHome(); // Initialisation of the physical IFW
121  }
122  else
123  {
132  }
133 
134  return true;
135 }
136 
137 /************************************************************************************
138 *
139 ************************************************************************************/
140 bool FilterIFW::WriteTTY(char *command)
141 {
142  char cmd[OPTEC_MAXLEN_CMD];
143  int errcode = 0;
144  char errmsg[MAXRBUF];
145  int nbytes_written = 0;
146 
147  snprintf(cmd, OPTEC_MAXLEN_CMD, "%s%s", command, "\n\r");
148  LOGF_DEBUG("CMD (%s)", cmd);
149 
150  if (!isSimulation())
151  {
152  if ((errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
153  {
154  tty_error_msg(errcode, errmsg, MAXRBUF);
155  LOGF_ERROR("%s", errmsg);
156  return false;
157  }
158  }
159  return true;
160 }
161 
162 /************************************************************************************
163 *
164 ************************************************************************************/
165 bool FilterIFW::ReadTTY(char *resp, char *simulation, int timeout)
166 {
167  int errcode = 0;
168  char errmsg[MAXRBUF];
169  char response[OPTEC_MAXLEN_RESP + 1];
170  int nbytes_read = 0;
171 
172  memset(response, 0, sizeof(response));
173 
174  if (isSimulation())
175  {
176  strncpy(response, simulation, sizeof(response));
177  nbytes_read = strlen(response) + 2; // +2 for simulation = "\n\r" see below
178  }
179  else
180  {
181  if ((errcode = tty_read_section(PortFD, response, 0xd, timeout, &nbytes_read)) != TTY_OK)
182  {
183  tty_error_msg(errcode, errmsg, MAXRBUF);
184  LOGF_ERROR("%s() TTY error: %s", __FUNCTION__, errmsg);
185  return false;
186  }
187  }
188 
189  if (nbytes_read <= 0)
190  {
191  LOG_ERROR("Controller error: Nothing returned by the IFW");
192  response[0] = '\0';
193  return false;
194  }
195 
196  response[nbytes_read - 2] = '\0'; //Remove control char from string (\n\r)
197  LOGF_DEBUG("RES (%s)", response);
198  strncpy(resp, response, /* sizeof(response)*/ OPTEC_MAXLEN_RESP + 1);
199  return true;
200 }
201 
202 /************************************************************************************
203 *
204 ************************************************************************************/
206 {
207  char response[OPTEC_MAXLEN_RESP + 1];
208  memset(response, 0, sizeof(response));
209  if (!WriteTTY((char *)"WSMODE"))
210  {
211  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
212  return false;
213  }
214 
215  if (!ReadTTY(response, (char *)"!", OPTEC_TIMEOUT))
216  {
217  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
218  return false;
219  }
220 
221  if (strcmp(response, "!") != 0)
222  {
223  LOG_ERROR("failed, wrong response from IFW");
224  LOGF_DEBUG("Response : (%s)", response);
225  return false;
226  }
227 
228  LOGF_DEBUG("Success, response from IFW is : %s", response);
229  LOG_INFO("IFW is online");
230 
231  return true;
232 }
233 
234 /************************************************************************************
235 *
236 ************************************************************************************/
238 {
239  DEBUGTAG();
240  char response[OPTEC_MAXLEN_RESP + 1];
241  memset(response, 0, sizeof(response));
242 
243  if (!WriteTTY((char *)"WEXITS"))
244  {
245  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
246  return false;
247  }
248 
249  if (!ReadTTY(response, (char *)"END", OPTEC_TIMEOUT))
250  {
251  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
252  return false;
253  }
254 
255  if (strcmp(response, "END") != 0)
256  {
257  LOG_ERROR("failed, wrong response from IFW");
258  return false;
259  }
260 
261  LOGF_DEBUG("IFW return in manual mode, response from IFW is : %s", response);
262  LOG_INFO("IFW is offline.");
263 
265 }
266 
267 /************************************************************************************
268 *
269 ************************************************************************************/
270 bool FilterIFW::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
271 {
272  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
273  {
274  // User has changed one or more names from filter related to the Wheel ID present in the IFW
275  if (strcmp(FilterNameTP->name, name) == 0)
276  {
277  // Only these chars are allowed to be able to the IFW display to show names correctly
278  std::regex rx("^[A-Z0-9=.#/%[:space:]-]{1,8}$");
279 
280  bool match = true;
281  //Check only if user allowed chars restriction
282  if (CharSetS[0].s == ISS_ON)
283  {
284  for (int i = 0; i < n; i++)
285  {
286  LOGF_DEBUG("FilterName request N°%d : %s", i, texts[i]);
287  match = std::regex_match(texts[i], rx);
288  if (!match)
289  break;
290  }
291  }
292 
293  if (match)
294  {
295  IUUpdateText(FilterNameTP, texts, names, n);
297  IDSetText(FilterNameTP, nullptr);
298  }
299  else
300  {
302  IDSetText(FilterNameTP, nullptr);
303  LOG_INFO("WARNING *****************************************************");
304  LOG_INFO(
305  "One of the filter name is not valid. It should not have more than 8 chars");
306  LOG_INFO("Valid chars are A to Z, 0 to 9 = . # / - percent or space");
307  LOG_INFO("WARNING *****************************************************");
308  return false;
309  }
310  return true;
311  }
312  }
313  return INDI::FilterWheel::ISNewText(dev, name, texts, names, n);
314 }
315 
316 /************************************************************************************
317 *
318 ************************************************************************************/
319 bool FilterIFW::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
320 {
321  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
322  {
323  if (strcmp(HomeSP.name, name) == 0)
324  {
325  bool result = true;
326  // User request the IWF reset (Home procedure will read the Wheel ID, load from EEProm the filters names and goes to filter N°1
327  IUUpdateSwitch(&HomeSP, states, names, n);
329  LOG_INFO("Executing Home command...");
330 
332  IDSetText(FilterNameTP, nullptr);
333 
334  if (!moveHome())
335  {
336  HomeSP.s = IPS_ALERT;
337  result = false;
338  }
339  else
340  {
341  LOG_DEBUG("Getting filter information...");
342 
343  if (!(GetFilterNames() && GetFilterPos() != 0))
344  {
345  HomeSP.s = IPS_ALERT;
346  result = false;
347  }
348  }
349 
350  IDSetSwitch(&HomeSP, nullptr);
351  if (!result)
352  {
353  LOGF_INFO("%s() failed to get information", __FUNCTION__);
354  LOG_INFO("Please check unit and press 'Home' button");
355  return false;
356  }
357 
358  return true;
359  }
360 
361  if (strcmp(FilterNbrSP.name, name) == 0)
362  {
363  IUUpdateSwitch(&FilterNbrSP, states, names, n);
364 
365  // Is simulation active, User can change from 5 positions wheel to 6, 8 or 9 ones
366  // Check if selection is different from active one
367 
368  if ((FilterNbrS[0].s == ISS_ON) & (FilterSlotN[0].max != 5))
369  {
370  strncpy(filterSim, filterSim5, sizeof(filterSim));
372  }
373  else if ((FilterNbrS[1].s == ISS_ON) & (FilterSlotN[0].max != 6))
374  {
375  strncpy(filterSim, filterSim6, sizeof(filterSim));
377  }
378  else if ((FilterNbrS[2].s == ISS_ON) & (FilterSlotN[0].max != 8))
379  {
380  strncpy(filterSim, filterSim8, sizeof(filterSim));
382  }
383  else if ((FilterNbrS[3].s == ISS_ON) & (FilterSlotN[0].max != 9))
384  {
385  strncpy(filterSim, filterSim9, sizeof(filterSim));
387  }
388  else
389  FilterNbrSP.s = IPS_OK;
390 
391  if (FilterNbrSP.s == IPS_ALERT)
392  {
393  IDSetSwitch(&FilterNbrSP, "%s() failed to change number of filters", __FUNCTION__);
394  return false;
395  }
396  else
397  IDSetSwitch(&FilterNbrSP, nullptr);
398 
399  return true;
400  }
401 
402  // Set switch from user selection to allowed use of all chars or restricted to display IFW
403  // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ=.#/-%
404  if (strcmp(CharSetSP.name, name) == 0)
405  {
406  IUUpdateSwitch(&CharSetSP, states, names, n);
407  CharSetSP.s = IPS_OK;
408  IDSetSwitch(&CharSetSP, nullptr);
409  return true;
410  }
411  }
412 
413  return INDI::FilterWheel::ISNewSwitch(dev, name, states, names, n);
414 }
415 
416 /************************************************************************************
417 *
418 ************************************************************************************/
420 {
421  // toogle buttons to select 5 or 8 filters depend if Simulation active or not
422  if (enable)
423  {
424  if (isConnected())
425  {
427  }
428  }
429  else
431 }
432 
433 /************************************************************************************
434 *
435 ************************************************************************************/
437 {
438  // not use with IFW
439 }
440 
441 /************************************************************************************
442 *
443 ************************************************************************************/
445 {
446  DEBUGTAG();
447  bool result = true;
448  char cmd[32] = {0};
449  char response[OPTEC_MAXLEN_RESP + 1];
450 
451  memset(response, 0, sizeof(response));
452  snprintf(cmd, 32, "%s%d", "WGOTO", f);
453 
455  IDSetNumber(&FilterSlotNP, "*** Moving to filter n° %d ***", f);
456 
457  if (!WriteTTY(cmd))
458  {
459  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
460  result = false;
461  }
462  else
463  {
464  if (isSimulation())
465  {
466  // Time depend of rotation direction. Goes via shortest way
467  int maxFilter = FilterSlotN[0].max;
468  int way1, way2;
469  if (f > actualSimFilter)
470  {
471  // CW calcul
472  way1 = f - actualSimFilter;
473  // CCW calcul
474  way2 = actualSimFilter + maxFilter - f;
475  }
476  else
477  {
478  // CCW calcul
479  way1 = actualSimFilter - f;
480  // CW calcul
481  way2 = maxFilter - actualSimFilter + f;
482  }
483  // About 2 second to change 1 position
484  if (way1 < way2)
485  sleep(2 * way1);
486  else
487  sleep(2 * way2);
488 
489  // Save actual value for Simulation
490  actualSimFilter = f;
491  }
492 
493  if (!ReadTTY(response, (char *)"*", OPTEC_TIMEOUT_MOVE))
494  {
495  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
496  result = false;
497  }
498  else if (strncmp(response, "*", 1) != 0)
499  {
500  LOGF_INFO("Error: %s", response);
501  PRINT_ER(response);
502  result = false;
503  }
504  }
505 
506  if (!result)
507  {
509  IDSetNumber(&FilterSlotNP, "*** UNABLE TO SELECT THE FILTER ***");
510  return false;
511  }
512 
513  // As to be called when filter has moved to new position:
515 
517  IDSetNumber(&FilterSlotNP, "Selected filter position reached");
518  return true;
519 }
520 
521 /************************************************************************************
522 *
523 ************************************************************************************/
525 {
526  DEBUGTAG();
527  bool result = true;
528  char filterName[MAXINDINAME];
529  char filterLabel[MAXINDILABEL];
530  char filterList[OPTEC_MAXLEN_NAMES + 9]; // tempo string used fo display filtername debug information
531  char response[OPTEC_MAXLEN_RESP + 1];
532  int lenResponse = 0; // Nbr of char in the response string
533  int maxFilter = 0;
534 
535  memset(response, 0, sizeof(response));
536 
538  IDSetText(FilterNameTP, nullptr);
539 
540  if (!WriteTTY((char *)"WREAD"))
541  {
542  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
543  result = false;
544  }
545  else if (!ReadTTY(response, filterSim, OPTEC_TIMEOUT))
546  {
547  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
548  result = false;
549  }
550 
551  if (result)
552  {
553  // Check the size of response to know if this is a 5 or 8 position wheel as from R2.x IFW support both
554  lenResponse = strlen(response);
555 
556  switch (lenResponse)
557  {
558  case 40:
559  maxFilter = 5;
560  break;
561  case 48:
562  maxFilter = 6;
563  break;
564  case 64:
565  maxFilter = 8;
566  break;
567  case 72:
568  maxFilter = 9;
569  break;
570  default:
571  maxFilter = 0; // Means error somewhere
572  }
573 
574  LOGF_DEBUG("Length of response %d", lenResponse);
575  LOGF_DEBUG("MaxFilter %d", maxFilter);
576  if (maxFilter != 0)
577  {
578  LOGF_DEBUG("Success, response from IFW is : %s", response);
579 
580  // Start parsing from IFW message
581  char *p = response;
582  char filterNameIFW[OPTEC_MAX_FILTER][9];
583  filterList[0] = '\0';
584 
585  for (int i = 0; i < maxFilter; i++)
586  {
587  strncpy(filterNameIFW[i], p, OPTEC_LEN_FLTNAME);
588  filterNameIFW[i][OPTEC_LEN_FLTNAME] = '\0';
589  p = p + OPTEC_LEN_FLTNAME;
590  LOGF_DEBUG("filterNameIFW[%d] : %s", i, filterNameIFW[i]);
591  strncat(filterList, filterNameIFW[i], OPTEC_LEN_FLTNAME);
592  strcat(filterList, "/");
593  }
594  filterList[strlen(filterList) - 1] = '\0'; //Remove last "/"
595 
596  LOG_DEBUG("Redo filters name list");
597  // Set new max value on the filter_slot property
598  FilterSlotN[0].max = maxFilter;
599  if (isSimulation())
600  FilterSlotN[0].value = actualSimFilter = 1;
602  IDSetNumber(&FilterSlotNP, nullptr);
603 
605 
606  if (FilterNameT != nullptr)
607  {
608  for (int i = 0; i < FilterNameTP->ntp; i++)
609  free(FilterNameT[i].text);
610  delete [] FilterNameT;
611  }
612 
613  FilterNameT = new IText[maxFilter];
614  memset(FilterNameT, 0, sizeof(IText) * maxFilter);
615 
616  for (int i = 0; i < maxFilter; i++)
617  {
618  snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
619  snprintf(filterLabel, MAXINDILABEL, "Filter n° %d", i + 1);
620  IUFillText(&FilterNameT[i], filterName, filterLabel, filterNameIFW[i]);
621  }
622 
623  IUFillTextVector(FilterNameTP, FilterNameT, maxFilter, getDeviceName(), "FILTER_NAME", "Filters", FilterSlotNP.group,
624  IP_RW, 0, IPS_OK);
626 
627  // filterList only use for purpose information
628  // Remove space from filterList
629  char *withSpace = filterList;
630  char *withoutSpace = filterList;
631  while (*withSpace != '\0')
632  {
633  if (*withSpace != ' ')
634  {
635  *withoutSpace = *withSpace;
636  withoutSpace++;
637  }
638  withSpace++;
639  }
640  *withoutSpace = '\0';
641 
642  IDSetText(FilterNameTP, "IFW Filters name -> %s", filterList);
643  return true;
644  }
645  else
646  LOGF_ERROR("List of filters name is wrong Nbr char red are: %s", lenResponse);
647  }
648 
650  LOG_ERROR("Failed to read filter names!");
651  IDSetText(FilterNameTP, nullptr);
652  return false;
653 }
654 
655 /************************************************************************************
656 *
657 ************************************************************************************/
659 {
660  DEBUGTAG();
661  bool result = true;
662  char cmd[72] = {0};
663  char tempo[OPTEC_LEN_FLTNAME + 1];
664  char response[OPTEC_MAXLEN_RESP + 1];
665  int tempolen;
666  memset(response, 0, sizeof(response));
667 
670  WheelIDTP.s = IPS_BUSY;
671  IDSetText(FilterNameTP, "*** Saving filters name to IFW... ***");
672  IDSetNumber(&FilterSlotNP, nullptr);
673  IDSetText(&WheelIDTP, nullptr);
674 
675  snprintf(cmd, 8, "WLOAD%s*", WheelIDT[0].text);
676 
677  for (int i = 0; i < FilterSlotN[0].max; i++)
678  {
679  // Prepare string in tempo with blank space at right to complete to 8 chars for each filter name
680  memset(tempo, ' ', sizeof(tempo));
681  //Check max len of 8 char for the filter name
682  tempolen = strlen(FilterNameT[i].text);
683  if (tempolen > OPTEC_LEN_FLTNAME)
684  tempolen = OPTEC_LEN_FLTNAME;
685  //memcpy(tempo + (8 - tempolen), FilterNameT[i].text, tempolen); // spaces at begin of name
686  memcpy(tempo, FilterNameT[i].text, tempolen); // spaces at the end of name
687  tempo[8] = '\0';
688  strcat(cmd, tempo);
689  strncpy(FilterNameT[i].text, tempo, OPTEC_LEN_FLTNAME);
690  FilterNameT[i].text[OPTEC_LEN_FLTNAME] = '\0';
691 
692  LOGF_DEBUG("Value of the command :%s", cmd);
693  //memset(response, 0, sizeof(tempo));
694  }
695 
696  LOGF_DEBUG("Length of the command to write to IFW = %d", strlen(cmd));
697 
698  if (isSimulation())
699  {
700  strncpy(filterSim, cmd + 7, OPTEC_MAXLEN_NAMES);
702  }
703 
704  if (!WriteTTY(cmd))
705  {
706  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
708  IDSetText(FilterNameTP, nullptr);
709  result = false;
710  // Have to wait at least 10 ms for EEPROM writing before next command
711  // Wait 50 mS to be safe
712  usleep(50000);
713  }
714  else
715  {
716  if (!ReadTTY(response, (char *)"!", OPTEC_TIMEOUT))
717  {
718  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
719  result = false;
720  }
721  else
722  {
723  if (strncmp(response, "ER=", 3) == 0)
724  {
725  LOGF_INFO("Error: %s", response);
726  PRINT_ER(response);
727  result = false;
728  }
729  }
730  }
731 
732  if (!result)
733  {
735  IDSetText(FilterNameTP, "*** UNABLE TO WRITE FILTERS NAME ***");
736  return false;
737  }
738 
739  LOG_INFO("Filters name are saved in IFW");
740 
741  // Interface not ready before the message "DATA OK" disapear from the display IFW
742  for (int i = OPTEC_WAIT_DATA_OK; i > 0; i--)
743  {
744  LOGF_INFO("Please wait for HOME command start... %d", i);
745  sleep(1);
746  }
747 
748  // Do HOME command to load EEProm new names and getFilter to read new value to validate
750  IDSetText(FilterNameTP, nullptr);
751 
752  return true;
753 }
754 
755 /************************************************************************************
756 *
757 ************************************************************************************/
759 {
760  DEBUGTAG();
761  bool result = true;
762  char response[OPTEC_MAXLEN_RESP + 1];
763 
764  memset(response, 0, sizeof(response));
765 
766  WheelIDTP.s = IPS_BUSY;
767  IDSetText(&WheelIDTP, nullptr);
768 
769  if (!WriteTTY((char *)"WIDENT"))
770  {
771  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
772  result = false;
773  }
774  else
775  {
776  if (!ReadTTY(response, (char *)"C", OPTEC_TIMEOUT))
777  {
778  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
779  result = false;
780  }
781  else if (strncmp(response, "ER=", 3) == 0)
782  {
783  LOGF_INFO("Get wheel ID error: %s", response);
784  PRINT_ER(response);
785  result = false;
786  }
787  }
788  if (!result)
789  {
791  IDSetText(&WheelIDTP, "*** UNABLE TO GET WHEEL ID ***");
792  return false;
793  }
794 
795  WheelIDTP.s = IPS_OK;
796  IUSaveText(&WheelIDT[0], response);
797  IDSetText(&WheelIDTP, "IFW wheel active is %s", response);
798 
799  return true;
800 }
801 
802 /************************************************************************************
803 *
804 ************************************************************************************/
806 {
807  DEBUGTAG();
808  int result = 1;
809  char response[OPTEC_MAXLEN_RESP + 1];
810  char filter[2] = {0};
811 
812  memset(response, 0, sizeof(response));
813 
815  IDSetNumber(&FilterSlotNP, nullptr);
816 
817  if (!WriteTTY((char *)"WFILTR"))
818  {
819  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
820  result = -1;
821  }
822  else
823  {
824  // actualSimFilter for simulation value. int value need to be char*
825  snprintf(filter, 2, "%d", actualSimFilter);
826 
827  if (!ReadTTY(response, filter, OPTEC_TIMEOUT))
828  {
829  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
830  result = -1;
831  }
832  }
833 
834  if (result == -1)
835  {
837  IDSetNumber(&FilterSlotNP, "*** UNABLE TO GET ACTIVE FILTER ***");
838  return result;
839  }
840 
841  result = atoi(response);
842  FilterSlotN[0].value = result;
844  IDSetNumber(&FilterSlotNP, "IFW filter active is n° %s -> %s", response, FilterNameT[result - 1].text);
845  return result;
846 }
847 
848 /************************************************************************************
849 *
850 ************************************************************************************/
852 {
853  DEBUGTAG();
854  bool result = true;
855  char response[OPTEC_MAXLEN_RESP + 1];
856 
857  memset(response, 0, sizeof(response));
858 
859  HomeSP.s = IPS_BUSY;
860  WheelIDTP.s = IPS_BUSY;
862  IDSetSwitch(&HomeSP, "*** Initialisation of the IFW. Please wait... ***");
863  IDSetText(&WheelIDTP, nullptr);
864  IDSetNumber(&FilterSlotNP, nullptr);
865 
866  if (!WriteTTY((char *)"WHOME"))
867  {
868  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
869  result = false;
870  }
871  else
872  {
873  if (isSimulation())
874  sleep(10); // About the same time as real filter
875 
876  if (!ReadTTY(response, (char *)"A", OPTEC_TIMEOUT_WHOME))
877  {
878  LOGF_ERROR("(Function %s()) failed to read from TTY", __FUNCTION__);
879  result = false;
880  }
881  else
882  {
883  if (strncmp(response, "ER=", 3) == 0)
884  {
885  LOGF_INFO("Move to Home error: %s", response);
886  PRINT_ER(response);
887  result = false;
888  }
889  }
890  }
891 
892  if (!result || !GetWheelID() || !GetFilterNames() || (GetFilterPos() <= 0))
893  {
894  HomeSP.s = IPS_ALERT;
896  IDSetSwitch(&HomeSP, "*** INITIALISATION FAILED ***");
897  return false;
898  }
899 
900  HomeSP.s = IPS_OK;
901  WheelIDTP.s = IPS_OK;
902  IDSetSwitch(&HomeSP, "IFW ready");
903  return true;
904 }
905 
906 /************************************************************************************
907 *
908 ************************************************************************************/
910 {
911  DEBUGTAG();
912  bool result = true;
913  char response[OPTEC_MAXLEN_RESP + 1];
914 
915  memset(response, 0, sizeof(response));
916 
918  IDSetText(&FirmwareTP, nullptr);
919 
920  if (!WriteTTY((char *)"WVAAAA"))
921  {
922  LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
923  result = false;
924  }
925  else
926  {
927  if (!ReadTTY(response, (char *)"V= 2.04", OPTEC_TIMEOUT_FIRMWARE))
928  {
929  LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
930  result = false;
931  }
932  else if (strncmp(response, "ER=", 3) == 0)
933  {
934  LOGF_INFO("Get wheel ID error: %s", response);
935  PRINT_ER(response);
936  result = false;
937  }
938  }
939  if (!result)
940  {
942  IDSetText(&FirmwareTP, "*** UNABLE TO GET FIRMWARE ***");
943  return false;
944  }
945 
946  // remove chars fomr the string to get only the nzuméric value of the Firmware version
947  char *p = nullptr;
948 
949  for (int i = 0; i < (int)strlen(response); i++)
950  {
951  if (isdigit(response[i]) != 0)
952  {
953  p = response + i;
954  break;
955  }
956  }
957 
958  FirmwareTP.s = IPS_OK;
959  IUSaveText(&FirmwareT[0], p);
960  IDSetText(&FirmwareTP, "IFW Firmware is %s", response);
961 
962  return true;
963 }
964 
965 /************************************************************************************
966 *
967 ************************************************************************************/
969 {
971 
974 
975  return true;
976 }
977 
978 /************************************************************************************
979 *
980 ************************************************************************************/
981 bool FilterIFW::loadConfig(bool silent, const char *property)
982 {
983  bool result;
984 
985  if (property == nullptr)
986  {
987  result = INDI::DefaultDevice::loadConfig(silent, "CHARSET");
988  result = (INDI::DefaultDevice::loadConfig(silent, "FILTER_NBR") && result);
989  result = (INDI::DefaultDevice::loadConfig(silent, "USEJOYSTICK") && result);
990  result = (INDI::DefaultDevice::loadConfig(silent, "JOYSTICKSETTINGS") && result);
991  }
992  else
993  result = INDI::DefaultDevice::loadConfig(silent, property);
994 
995  return result;
996 }
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
ITextVectorProperty WheelIDTP
Definition: ifwoptec.h:107
ISwitch FilterNbrS[4]
Definition: ifwoptec.h:116
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: ifwoptec.cpp:104
int GetFilterPos()
Definition: ifwoptec.cpp:805
virtual bool loadConfig(bool silent=false, const char *property=nullptr) override
Load the last saved configuration file.
Definition: ifwoptec.cpp:981
ISwitch HomeS[1]
Definition: ifwoptec.h:112
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: ifwoptec.cpp:436
bool GetFirmware()
Definition: ifwoptec.cpp:909
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
Definition: ifwoptec.cpp:419
virtual bool GetFilterNames() override
Obtains a list of filter names from the hardware and initializes the FilterNameTP property....
Definition: ifwoptec.cpp:524
bool WriteTTY(char *command)
Definition: ifwoptec.cpp:140
ISwitch CharSetS[2]
Definition: ifwoptec.h:120
virtual bool Disconnect() override
Disconnect from device.
Definition: ifwoptec.cpp:237
bool GetWheelID()
Definition: ifwoptec.cpp:758
bool ReadTTY(char *resp, char *simulation, int timeout)
Definition: ifwoptec.cpp:165
bool moveHome()
Definition: ifwoptec.cpp:851
ISwitchVectorProperty CharSetSP
Definition: ifwoptec.h:119
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: ifwoptec.cpp:968
ISwitchVectorProperty HomeSP
Definition: ifwoptec.h:111
ITextVectorProperty FirmwareTP
Definition: ifwoptec.h:123
ISwitchVectorProperty FilterNbrSP
Definition: ifwoptec.h:115
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: ifwoptec.cpp:270
virtual bool SetFilterNames() override
Set filter names as defined by the client for each filter position. The desired filter names are stor...
Definition: ifwoptec.cpp:658
IText WheelIDT[1]
Definition: ifwoptec.h:108
char filterSim[OPTEC_MAXLEN_NAMES+1]
Definition: ifwoptec.h:130
virtual const char * getDefaultName() override
Definition: ifwoptec.cpp:54
virtual bool SelectFilter(int) override
Select a new filter position.
Definition: ifwoptec.cpp:444
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: ifwoptec.cpp:62
virtual bool Handshake() override
perform handshake with device to check communication
Definition: ifwoptec.cpp:205
IText FirmwareT[1]
Definition: ifwoptec.h:124
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: ifwoptec.cpp:319
int actualSimFilter
Definition: ifwoptec.h:127
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool updateProperties()
virtual bool Disconnect()
Disconnect from device.
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)
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
ITextVectorProperty * FilterNameTP
INumberVectorProperty FilterSlotNP
void SelectFilterDone(int newpos)
The child class calls this function when the hardware successfully finished selecting a new filter wh...
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Controller * controller
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Connection::Serial * serialConnection
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
void setFilterConnection(const uint8_t &value)
setFilterConnection Set Filter connection mode. Child class should call this in the constructor befor...
int PortFD
For Serial & TCP connections.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
const char * FILTER_TAB
FILTER_TAB Where all the properties for filter wheels are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
double max(void)
std::unique_ptr< FilterIFW > filter_ifw(new FilterIFW())
#define VERSION
Definition: ifwoptec.h:23
#define PRINT_ER(error)
Definition: ifwoptec.h:55
#define OPTEC_TIMEOUT_WHOME
Definition: ifwoptec.h:28
#define filterSim5
Definition: ifwoptec.h:39
#define filterSim8
Definition: ifwoptec.h:41
#define OPTEC_LEN_FLTNAME
Definition: ifwoptec.h:32
#define SUBVERSION
Definition: ifwoptec.h:24
#define OPTEC_MAXLEN_CMD
Definition: ifwoptec.h:33
#define OPTEC_TIMEOUT_FIRMWARE
Definition: ifwoptec.h:29
#define OPTEC_MAXLEN_NAMES
Definition: ifwoptec.h:35
#define OPTEC_MAXLEN_RESP
Definition: ifwoptec.h:34
#define OPTEC_WAIT_DATA_OK
Definition: ifwoptec.h:37
#define OPTEC_TIMEOUT
Definition: ifwoptec.h:26
#define OPTEC_MAX_FILTER
Definition: ifwoptec.h:31
#define filterSim6
Definition: ifwoptec.h:40
#define filterSim9
Definition: ifwoptec.h:42
#define OPTEC_TIMEOUT_MOVE
Definition: ifwoptec.h:27
#define DEBUGTAG()
Definition: ifwoptec.h:71
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
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
#define MAXINDILABEL
Definition: indiapi.h:192
@ ISR_1OFMANY
Definition: indiapi.h:173
#define MAXINDINAME
Definition: indiapi.h:191
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 IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
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
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
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 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 IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
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_DEBUG(txt)
Definition: indilogger.h:75
#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
__u8 cmd[4]
Definition: pwc-ioctl.h:2
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
Definition: indilogger.cpp:339
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
Definition: indilogger.cpp:72
One text descriptor.
char group[MAXINDIGROUP]
Definition: indiapi.h:327
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250