Instrument Neutral Distributed Interface INDI 2.2.5
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
31std::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,
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,
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************************************************************************************/
140bool 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************************************************************************************/
165bool 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 snprintf(response, sizeof(response), "%s", simulation);
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************************************************************************************/
270bool 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 (FilterNameTP.isNameMatch(name))
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 FilterNameTP.update(texts, names, n);
298 }
299 else
300 {
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************************************************************************************/
319bool 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
333
334 if (!moveHome())
335 {
337 result = false;
338 }
339 else
340 {
341 LOG_DEBUG("Getting filter information...");
342
343 if (!(GetFilterNames() && GetFilterPos() != 0))
344 {
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) & (FilterSlotNP[0].getMax() != 5))
369 {
370 strncpy(filterSim, filterSim5, sizeof(filterSim));
372 }
373 else if ((FilterNbrS[1].s == ISS_ON) & (FilterSlotNP[0].getMax() != 6))
374 {
375 strncpy(filterSim, filterSim6, sizeof(filterSim));
377 }
378 else if ((FilterNbrS[2].s == ISS_ON) & (FilterSlotNP[0].getMax() != 8))
379 {
380 strncpy(filterSim, filterSim8, sizeof(filterSim));
382 }
383 else if ((FilterNbrS[3].s == ISS_ON) & (FilterSlotNP[0].getMax() != 9))
384 {
385 strncpy(filterSim, filterSim9, sizeof(filterSim));
387 }
388 else
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);
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 // toggle 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 FilterSlotNP.apply("*** 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 = FilterSlotNP[0].getMax();
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 FilterSlotNP.apply("*** UNABLE TO SELECT THE FILTER ***");
510 return false;
511 }
512
513 // As to be called when filter has moved to new position:
515
517 FilterSlotNP.apply("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
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 snprintf(filterNameIFW[i], OPTEC_LEN_FLTNAME + 1, "%s", p);
588 filterNameIFW[i][OPTEC_LEN_FLTNAME] = '\0';
589 p = p + OPTEC_LEN_FLTNAME;
590 LOGF_DEBUG("filterNameIFW[%d] : %s", i, filterNameIFW[i]);
591 strcat(filterList, filterNameIFW[i]);
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 FilterSlotNP[0].setMax(maxFilter);
599 if (isSimulation())
600 FilterSlotNP[0].setValue(actualSimFilter = 1);
603
605
607
608 for (int i = 0; i < maxFilter; i++)
609 {
610 snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1);
611 snprintf(filterLabel, MAXINDILABEL, "Filter n° %d", i + 1);
612
613 INDI::WidgetText oneText;
614 oneText.fill(filterName, filterLabel, filterNameIFW[i]);
615 FilterNameTP.push(std::move(oneText));
616 }
617
618 FilterNameTP.fill(getDeviceName(), "FILTER_NAME", "Filters", FilterSlotNP.getGroupName(),
619 IP_RW, 0, IPS_OK);
622
623 // filterList only use for purpose information
624 // Remove space from filterList
625 char *withSpace = filterList;
626 char *withoutSpace = filterList;
627 while (*withSpace != '\0')
628 {
629 if (*withSpace != ' ')
630 {
631 *withoutSpace = *withSpace;
632 withoutSpace++;
633 }
634 withSpace++;
635 }
636 *withoutSpace = '\0';
637
638 FilterNameTP.apply("IFW Filters name -> %s", filterList);
639 return true;
640 }
641 else
642 LOGF_ERROR("List of filters name is wrong Nbr char red are: %s", lenResponse);
643 }
644
646 LOG_ERROR("Failed to read filter names!");
648 return false;
649}
650
651/************************************************************************************
652*
653************************************************************************************/
655{
656 DEBUGTAG();
657 bool result = true;
658 char cmd[72] = {0};
659 char tempo[OPTEC_LEN_FLTNAME + 1];
660 char response[OPTEC_MAXLEN_RESP + 1];
661 int tempolen;
662 memset(response, 0, sizeof(response));
663
667 FilterNameTP.apply("*** Saving filters name to IFW... ***");
669 IDSetText(&WheelIDTP, nullptr);
670
671 snprintf(cmd, 8, "WLOAD%s*", WheelIDT[0].text);
672
673 for (int i = 0; i < FilterSlotNP[0].getMax(); i++)
674 {
675 // Prepare string in tempo with blank space at right to complete to 8 chars for each filter name
676 memset(tempo, ' ', sizeof(tempo));
677 //Check max len of 8 char for the filter name
678 tempolen = strlen(FilterNameTP[i].getText());
679 if (tempolen > OPTEC_LEN_FLTNAME)
680 tempolen = OPTEC_LEN_FLTNAME;
681 //memcpy(tempo + (8 - tempolen), FilterNameT[i].text, tempolen); // spaces at begin of name
682 memcpy(tempo, FilterNameTP[i].getText(), tempolen); // spaces at the end of name
683 tempo[8] = '\0';
684 strcat(cmd, tempo);
685
686 LOGF_DEBUG("Value of the command :%s", cmd);
687 //memset(response, 0, sizeof(tempo));
688 }
689
690 LOGF_DEBUG("Length of the command to write to IFW = %d", strlen(cmd));
691
692 if (isSimulation())
693 {
694 strncpy(filterSim, cmd + 7, OPTEC_MAXLEN_NAMES);
696 }
697
698 if (!WriteTTY(cmd))
699 {
700 LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
703 result = false;
704 // Have to wait at least 10 ms for EEPROM writing before next command
705 // Wait 50 mS to be safe
706 usleep(50000);
707 }
708 else
709 {
710 if (!ReadTTY(response, (char *)"!", OPTEC_TIMEOUT))
711 {
712 LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
713 result = false;
714 }
715 else
716 {
717 if (strncmp(response, "ER=", 3) == 0)
718 {
719 LOGF_INFO("Error: %s", response);
720 PRINT_ER(response);
721 result = false;
722 }
723 }
724 }
725
726 if (!result)
727 {
729 FilterNameTP.apply("*** UNABLE TO WRITE FILTERS NAME ***");
730 return false;
731 }
732
733 LOG_INFO("Filters name are saved in IFW");
734
735 // Interface not ready before the message "DATA OK" disappear from the display IFW
736 for (int i = OPTEC_WAIT_DATA_OK; i > 0; i--)
737 {
738 LOGF_INFO("Please wait for HOME command start... %d", i);
739 sleep(1);
740 }
741
742 // Do HOME command to load EEProm new names and getFilter to read new value to validate
745
746 return true;
747}
748
749/************************************************************************************
750*
751************************************************************************************/
753{
754 DEBUGTAG();
755 bool result = true;
756 char response[OPTEC_MAXLEN_RESP + 1];
757
758 memset(response, 0, sizeof(response));
759
761 IDSetText(&WheelIDTP, nullptr);
762
763 if (!WriteTTY((char *)"WIDENT"))
764 {
765 LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
766 result = false;
767 }
768 else
769 {
770 if (!ReadTTY(response, (char *)"C", OPTEC_TIMEOUT))
771 {
772 LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
773 result = false;
774 }
775 else if (strncmp(response, "ER=", 3) == 0)
776 {
777 LOGF_INFO("Get wheel ID error: %s", response);
778 PRINT_ER(response);
779 result = false;
780 }
781 }
782 if (!result)
783 {
785 IDSetText(&WheelIDTP, "*** UNABLE TO GET WHEEL ID ***");
786 return false;
787 }
788
790 IUSaveText(&WheelIDT[0], response);
791 IDSetText(&WheelIDTP, "IFW wheel active is %s", response);
792
793 return true;
794}
795
796/************************************************************************************
797*
798************************************************************************************/
800{
801 DEBUGTAG();
802 int result = 1;
803 char response[OPTEC_MAXLEN_RESP + 1];
804 char filter[2] = {0};
805
806 memset(response, 0, sizeof(response));
807
810
811 if (!WriteTTY((char *)"WFILTR"))
812 {
813 LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
814 result = -1;
815 }
816 else
817 {
818 // actualSimFilter for simulation value. int value need to be char*
819 snprintf(filter, 2, "%d", actualSimFilter);
820
821 if (!ReadTTY(response, filter, OPTEC_TIMEOUT))
822 {
823 LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
824 result = -1;
825 }
826 }
827
828 if (result == -1)
829 if (result == -1)
830 {
832 FilterSlotNP.apply("*** UNABLE TO GET ACTIVE FILTER ***");
833 return result;
834 }
835
836 result = atoi(response);
837 FilterSlotNP[0].setValue(result);
839 FilterSlotNP.apply("IFW filter active is n° %s -> %s", response, FilterNameTP[result - 1].getText());
840 return result;
841}
842
843/************************************************************************************
844*
845************************************************************************************/
847{
848 DEBUGTAG();
849 bool result = true;
850 char response[OPTEC_MAXLEN_RESP + 1];
851
852 memset(response, 0, sizeof(response));
853
854 HomeSP.s = IPS_BUSY;
857 IDSetSwitch(&HomeSP, "*** Initialisation of the IFW. Please wait... ***");
858 IDSetText(&WheelIDTP, nullptr);
860
861 if (!WriteTTY((char *)"WHOME"))
862 {
863 LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
864 result = false;
865 }
866 else
867 {
868 if (isSimulation())
869 sleep(10); // About the same time as real filter
870
871 if (!ReadTTY(response, (char *)"A", OPTEC_TIMEOUT_WHOME))
872 {
873 LOGF_ERROR("(Function %s()) failed to read from TTY", __FUNCTION__);
874 result = false;
875 }
876 else
877 {
878 if (strncmp(response, "ER=", 3) == 0)
879 {
880 LOGF_INFO("Move to Home error: %s", response);
881 PRINT_ER(response);
882 result = false;
883 }
884 }
885 }
886
887 if (!result || !GetWheelID() || !GetFilterNames() || (GetFilterPos() <= 0))
888 {
891 IDSetSwitch(&HomeSP, "*** INITIALISATION FAILED ***");
892 return false;
893 }
894
895 HomeSP.s = IPS_OK;
897 IDSetSwitch(&HomeSP, "IFW ready");
898 return true;
899}
900
901/************************************************************************************
902*
903************************************************************************************/
905{
906 DEBUGTAG();
907 bool result = true;
908 char response[OPTEC_MAXLEN_RESP + 1];
909
910 memset(response, 0, sizeof(response));
911
913 IDSetText(&FirmwareTP, nullptr);
914
915 if (!WriteTTY((char *)"WVAAAA"))
916 {
917 LOGF_ERROR("(Function %s()) failed to write to TTY", __FUNCTION__);
918 result = false;
919 }
920 else
921 {
922 if (!ReadTTY(response, (char *)"V= 2.04", OPTEC_TIMEOUT_FIRMWARE))
923 {
924 LOGF_ERROR("(Function %s()) failed to read to TTY", __FUNCTION__);
925 result = false;
926 }
927 else if (strncmp(response, "ER=", 3) == 0)
928 {
929 LOGF_INFO("Get wheel ID error: %s", response);
930 PRINT_ER(response);
931 result = false;
932 }
933 }
934 if (!result)
935 {
937 IDSetText(&FirmwareTP, "*** UNABLE TO GET FIRMWARE ***");
938 return false;
939 }
940
941 // remove chars from the string to get only the nzuméric value of the Firmware version
942 char *p = nullptr;
943
944 for (int i = 0; i < (int)strlen(response); i++)
945 {
946 if (isdigit(response[i]) != 0)
947 {
948 p = response + i;
949 break;
950 }
951 }
952
954 IUSaveText(&FirmwareT[0], p);
955 IDSetText(&FirmwareTP, "IFW Firmware is %s", response);
956
957 return true;
958}
959
960/************************************************************************************
961*
962************************************************************************************/
964{
966
969
970 return true;
971}
972
973/************************************************************************************
974*
975************************************************************************************/
976bool FilterIFW::loadConfig(bool silent, const char *property)
977{
978 bool result;
979
980 if (property == nullptr)
981 {
982 result = INDI::DefaultDevice::loadConfig(silent, "CHARSET");
983 result = (INDI::DefaultDevice::loadConfig(silent, "FILTER_NBR") && result);
984 result = (INDI::DefaultDevice::loadConfig(silent, "USEJOYSTICK") && result);
985 result = (INDI::DefaultDevice::loadConfig(silent, "JOYSTICKSETTINGS") && result);
986 }
987 else
988 result = INDI::DefaultDevice::loadConfig(silent, property);
989
990 return result;
991}
992
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:799
virtual bool loadConfig(bool silent=false, const char *property=nullptr) override
Load the last saved configuration file.
Definition ifwoptec.cpp:976
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:904
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:752
bool ReadTTY(char *resp, char *simulation, int timeout)
Definition ifwoptec.cpp:165
bool moveHome()
Definition ifwoptec.cpp:846
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:963
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:654
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
Initialize 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
INDI::PropertyText getText(const char *name) const
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.
INDI::PropertyNumber FilterSlotNP
INDI::PropertyText FilterNameTP
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
Initialize 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.
void push(WidgetView< T > &&item)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void resize(size_t size)
bool isNameMatch(const char *otherName) const
const char * getGroupName() const
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
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.
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:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
#define MAXINDILABEL
Definition indiapi.h:190
@ ISR_1OFMANY
Definition indiapi.h:171
#define MAXINDINAME
Definition indiapi.h:189
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:653
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition indidevapi.c:33
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
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:509
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition indidevapi.c:44
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition indidevapi.c:376
void 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:416
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:453
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
#define MAXRBUF
Definition indidriver.c:52
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#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 getDeviceName
uint8_t 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.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
void fill(const char *name, const char *label, const char *initialText)
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248