Instrument Neutral Distributed Interface INDI  2.0.2
wanderer_cover.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2015 Jasem Mutlaq. All rights reserved.
3 
4  Wanderer cover V3
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the Free
8  Software Foundation; either version 2 of the License, or (at your option)
9  any later version.
10 
11  This program is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 
21  The full GNU General Public License is included in this distribution in the
22  file called LICENSE.
23 *******************************************************************************/
24 
25 #include "wanderer_cover.h"
26 
27 #include "indicom.h"
29 
30 #include <cerrno>
31 #include <cstring>
32 #include <memory>
33 #include <termios.h>
34 #include <unistd.h>
35 #include <inttypes.h>
36 #include <sys/ioctl.h>
37 
38 // We declare an auto pointer to WandererCover.
39 static std::unique_ptr<WandererCover> wanderercover(new WandererCover());
40 #define PARK 1
41 #define DATA_BITS 8
42 #define FLAT_CMD 6
43 #define WANDERER_RESPONSE_SIZE 1
44 #define COMMAND_WAITING_TIME 120
45 
46 #define FIRST_SUPPORTED_VERSION "20220920"
47 
48 #define TAB_NAME_CONFIGURATION "Dust cover configuration"
49 
50 #define CLOSE_COVER_COMMAND "1000\n"
51 #define HANDSHAKE_COMMAND "1500001\n"
52 #define OPEN_COVER_COMMAND "1001\n"
53 #define TURN_OFF_LIGHT_PANEL_COMMAND "9999\n"
54 
55 # define SET_CURRENT_POSITION_TO_OPEN_POSITION "257\n"
56 # define SET_CURRENT_POSITION_TO_CLOSED_POSITION "256\n"
57 
58 
60 {
61  setVersion(1, 0);
62 }
63 
65 {
69 
72 
73  // Status
74  IUFillText(&StatusT[0], "Cover", "Cover", nullptr);
75  IUFillText(&StatusT[1], "Light", "Light", nullptr);
76  IUFillTextVector(&StatusTP, StatusT, 2, getDeviceName(), "Status", "Status", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
77 
78  // Firmware version
79  IUFillText(&FirmwareT[0], "Version", "Version", nullptr);
80  IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "Firmware", "Firmware", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
81 
82  // Configuration
83  IUFillSwitch(&ControlPositionPositiveDegreesConfigurationV[PLUS_1_DEGREE], "PLUS_1_DEGREE", "+ 1°", ISS_OFF);
84  IUFillSwitch(&ControlPositionPositiveDegreesConfigurationV[PLUS_10_DEGREE], "PLUS_10_DEGREE", "+ 10°", ISS_OFF);
85  IUFillSwitch(&ControlPositionPositiveDegreesConfigurationV[PLUS_50_DEGREE], "PLUS_50_DEGREE", "+ 50°", ISS_OFF);
86  IUFillSwitchVector(&ControlPositionPositiveDegreesConfigurationVP, ControlPositionPositiveDegreesConfigurationV, 3,
87  getDeviceName(), "Open dust cap", "Open dust cap", TAB_NAME_CONFIGURATION, IP_RW,
88  ISR_ATMOST1, 0, IPS_IDLE);
89 
90  IUFillSwitch(&ControlPositionNegativeDegreesConfigurationV[MINUS_1_DEGREE], "MINUS_1_DEGREE", "- 1°", ISS_OFF);
91  IUFillSwitch(&ControlPositionNegativeDegreesConfigurationV[MINUS_10_DEGREE], "MINUS_10_DEGREE", "- 10°", ISS_OFF);
92  IUFillSwitch(&ControlPositionNegativeDegreesConfigurationV[MINUS_50_DEGREE], "MINUS_50_DEGREE", "- 50°", ISS_OFF);
93  IUFillSwitchVector(&ControlPositionNegativeDegreesConfigurationVP, ControlPositionNegativeDegreesConfigurationV, 3,
94  getDeviceName(), "Close dust cap", "Close dust cap", TAB_NAME_CONFIGURATION, IP_RW,
95  ISR_ATMOST1, 0, IPS_IDLE);
96 
97  IUFillSwitch(&DefinePositionConfigurationV[SET_CURRENT_POSITION_OPEN], "Set current position as open",
98  " 1 - Set current position as open", ISS_OFF);
99  IUFillSwitch(&DefinePositionConfigurationV[SET_CURRENT_POSITION_CLOSE], "Set current position as close",
100  "2 - Set current position as close", ISS_OFF);
101  IUFillSwitchVector(&DefinePositionConfigurationVP, DefinePositionConfigurationV, 2, getDeviceName(), "Define position",
102  "Action", TAB_NAME_CONFIGURATION, IP_RW,
103  ISR_ATMOST1, 0, IPS_IDLE);
104 
105 
106  LightIntensityN[0].min = 1;
107  LightIntensityN[0].max = 255;
108  LightIntensityN[0].step = 10;
109 
110 
111 
112  serialConnection = new Connection::Serial(this);
114  serialConnection->registerHandshake([&]()
115  {
116  return Handshake();
117  });
118  registerConnection(serialConnection);
119 
120  return true;
121 }
122 
123 bool WandererCover::Handshake()
124 {
125  if (isSimulation())
126  {
127  LOGF_INFO("Connected successfuly to simulated %s. Retrieving startup data...", getDeviceName());
128 
129  // SetTimer(getCurrentPollingPeriod());
130  IUSaveText(&FirmwareT[0], "Simulation version");
131  IDSetText(&FirmwareTP, nullptr);
132 
133  updateCoverStatus((char*) "0");
134 
135  setLightBoxStatusAsSwitchedOff();
136 
137  NumberOfStepsBeetweenOpenAndCloseState = 0;
138  setNumberOfStepsStatusValue(NumberOfStepsBeetweenOpenAndCloseState);
139 
140  syncDriverInfo();
141  return true;
142  }
143  PortFD = serialConnection->getPortFD();
144  tcflush(PortFD, TCIOFLUSH);
145  int nbytes_read_name = 0, nbytes_written = 0, rc = -1;
146  char name[64] = {0};
147  LOGF_DEBUG("CMD <%s>", HANDSHAKE_COMMAND);
148  if ((rc = tty_write_string(PortFD, HANDSHAKE_COMMAND, &nbytes_written)) != TTY_OK)
149  {
150  char errorMessage[MAXRBUF];
151  tty_error_msg(rc, errorMessage, MAXRBUF);
152  LOGF_ERROR("Serial write error: %s", errorMessage);
153  return false;
154  }
155 
156  if ((rc = tty_read_section(PortFD, name, 'A', 5, &nbytes_read_name)) != TTY_OK)
157  {
158  char errorMessage[MAXRBUF];
159  tty_error_msg(rc, errorMessage, MAXRBUF);
160  LOGF_ERROR("Device read error: %s", errorMessage);
161  return false;
162  }
163  name[nbytes_read_name - 1] = '\0';
164  LOGF_DEBUG("Name : <%s>", name);
165 
166  int nbytes_read_version = 0;
167  char version[64] = {0};
168  if ((rc = tty_read_section(PortFD, version, 'A', 5, &nbytes_read_version)) != TTY_OK)
169  {
170  char errorMessage[MAXRBUF];
171  tty_error_msg(rc, errorMessage, MAXRBUF);
172  LOGF_ERROR("Device read error: %s", errorMessage);
173  LOGF_ERROR("You have an old firmware. This version is not supported. You should update the device as described here : %s",
174  "https://www.wandererastro.com/en/col.jsp?id=106");
175  return true;
176  }
177 
178  displayConfigurationMessage();
179  version[nbytes_read_version - 1] = '\0';
180  LOGF_INFO("Version : %s", version);
181  IUSaveText(&FirmwareT[0], version);
182  IDSetText(&FirmwareTP, nullptr);
183 
184 
185  // Cover status
186  char cover_state[64] = {0};
187  int nbytes_read_cover_state = 0;
188 
189  if ((rc = tty_read_section(PortFD, cover_state, 'A', 5, &nbytes_read_cover_state)) != TTY_OK)
190  {
191  char errorMessage[MAXRBUF];
192  tty_error_msg(rc, errorMessage, MAXRBUF);
193  LOGF_ERROR("Device read error: %s", errorMessage);
194  return false;
195  }
196  cover_state[nbytes_read_cover_state - 1] = '\0';
197  LOGF_INFO("Cover state : %s", cover_state);
198  updateCoverStatus(cover_state);
199 
200  // Number of steps
201  char number_of_steps[64] = {0};
202  int nbytes_read_number_of_steps = 0;
203 
204  if ((rc = tty_read_section(PortFD, number_of_steps, 'A', 5, &nbytes_read_number_of_steps)) != TTY_OK)
205  {
206  char errorMessage[MAXRBUF];
207  tty_error_msg(rc, errorMessage, MAXRBUF);
208  LOGF_ERROR("Device read error: %s", errorMessage);
209  return false;
210  }
211  number_of_steps[nbytes_read_number_of_steps - 1] = '\0';
212  LOGF_INFO("Number of steps between open and close states : %s", cover_state);
213  NumberOfStepsBeetweenOpenAndCloseState = sscanf(number_of_steps, "%d", &NumberOfStepsBeetweenOpenAndCloseState);
214  if (NumberOfStepsBeetweenOpenAndCloseState == 0)
215  {
216  LOGF_ERROR("The number of steps is 0 meaning the falt panel may hit an obstacle. You should define opening and closing position first.",
217  "");
218  }
219  setNumberOfStepsStatusValue(NumberOfStepsBeetweenOpenAndCloseState);
220 
221  setLightBoxStatusAsSwitchedOff();
222 
223  LOGF_INFO("Handshake successful:%s", name);
224  tcflush(PortFD, TCIOFLUSH);
225  return true;
226 }
227 
228 void WandererCover::updateCoverStatus(char* res)
229 {
230  if (strcmp(res, "0") == 0)
231  {
232  setParkCapStatusAsClosed();
233  }
234  else if (strcmp(res, "1") == 0)
235  {
236  setParkCapStatusAsOpen();
237  }
238  else if (strcmp(res, "255") == 0)
239  {
240  LOGF_INFO("No cover status information available. You should first open/close the cover.", "");
241  }
242 }
243 
244 void WandererCover::ISGetProperties(const char *dev)
245 {
247 
248  // Get Light box properties
250 }
251 
253 {
255 
256  if (isConnected())
257  {
261  defineProperty(&StatusTP);
262  defineProperty(&FirmwareTP);
263 
264  defineProperty(&ControlPositionPositiveDegreesConfigurationVP);
265  defineProperty(&ControlPositionNegativeDegreesConfigurationVP);
266  defineProperty(&DefinePositionConfigurationVP);
267 
269 
270  getStartupData();
271  }
272  else
273  {
277  deleteProperty(StatusTP.name);
278  deleteProperty(FirmwareTP.name);
279 
280  deleteProperty(ControlPositionPositiveDegreesConfigurationVP.name);
281  deleteProperty(ControlPositionNegativeDegreesConfigurationVP.name);
282  deleteProperty(DefinePositionConfigurationVP.name);
283 
285  }
286  return true;
287 }
288 
290 {
291  return "Wanderer Cover v3";
292 }
293 
294 bool WandererCover::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
295 {
296  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
297  {
298  if (processLightBoxNumber(dev, name, values, names, n))
299  return true;
300  }
301 
302  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
303 }
304 
305 bool WandererCover::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
306 {
307  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
308  {
309  if (processLightBoxText(dev, name, texts, names, n))
310  return true;
311  }
312 
313  return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
314 }
315 
316 bool WandererCover::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
317 {
318  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
319  {
320  if (processDustCapSwitch(dev, name, states, names, n))
321  return true;
322 
323  if (processLightBoxSwitch(dev, name, states, names, n))
324  return true;
325 
326  if (processConfigurationButtonSwitch(dev, name, states, names, n))
327  return true;
328  }
329 
330  return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
331 }
332 
334 {
335  snoopLightBox(root);
336 
338 }
339 
341 {
343 
344  return saveLightBoxConfigItems(fp);
345 }
346 
347 bool WandererCover::getStartupData()
348 {
349  // // Closing cover
350  // IUSaveText(&StatusT[0], "Closed");
351  // IUResetSwitch(&ParkCapSP);
352  // ParkCapS[0].s = ISS_ON;
353  // ParkCapSP.s = IPS_OK;
354  // LOG_INFO("Cover assumed as closed.");
355  // IDSetSwitch(&ParkCapSP, nullptr);
356 
357  // // Switching off lamp
358  // IUSaveText(&StatusT[1], "Off");
359  // LightS[0].s = ISS_OFF;
360  // LightS[1].s = ISS_ON;
361  // IDSetSwitch(&LightSP, nullptr);
362  // LightIntensityN[0].value = 0;
363  // LOG_INFO("Light assumed as off.");
364  // IDSetNumber(&LightIntensityNP, nullptr);
365 
366  return true;
367 }
368 
370 {
371  if (NumberOfStepsBeetweenOpenAndCloseState == 0)
372  {
373  LOGF_ERROR("The number of steps is 0 meaning the falt panel may hit an obstacle. You should define opening and closing position first.",
374  "");
375  return IPS_ALERT;
376  }
377 
378  if (isSimulation())
379  {
380  setParkCapStatusAsClosed();
381  return IPS_OK;
382  }
383 
384  // Not sure why the TTY sends crappy data there
385  char response[20];
386  if (!sendCommand(CLOSE_COVER_COMMAND, response, true))
387  return IPS_ALERT;
388 
389  if (hasWandererSentAnError(response))
390  {
391  LOG_ERROR("You need to configure Open and closed position first in 'Dust cover configuration' tab.");
392  return IPS_ALERT;
393  }
394  setParkCapStatusAsClosed();
395 
396  return IPS_OK;
397 }
398 
399 void WandererCover::setParkCapStatusAsClosed()
400 {
401  IUSaveText(&StatusT[0], "Closed");
403  ParkCapS[0].s = ISS_ON;
404  ParkCapSP.s = IPS_OK;
405  LOG_INFO("Cover closed.");
406  IDSetSwitch(&ParkCapSP, nullptr);
407 }
408 
410 {
411  if (NumberOfStepsBeetweenOpenAndCloseState == 0)
412  {
413  LOG_ERROR("The number of steps is 0 meaning the falt panel may hit an obstacle. You should define opening and closing position first.");
414  return IPS_ALERT;
415  }
416 
417  if (isSimulation())
418  {
419  setParkCapStatusAsOpen();
420  return IPS_OK;
421  }
422 
423  // Not sure why the TTY sends crappy data there
424  char response[20];
425  if (!sendCommand(OPEN_COVER_COMMAND, response, true))
426  return IPS_ALERT;
427 
428  if (hasWandererSentAnError(response))
429  {
430  displayConfigurationMessage();
431  return IPS_ALERT;
432  }
433 
434  setParkCapStatusAsOpen();
435  return IPS_OK;
436 }
437 
438 void WandererCover::setParkCapStatusAsOpen()
439 {
440  IUSaveText(&StatusT[0], "Open");
442  ParkCapS[1].s = ISS_ON;
443  ParkCapSP.s = IPS_OK;
444  LOG_INFO("Cover open.");
445  IDSetSwitch(&ParkCapSP, nullptr);
446 }
447 
449 {
450  if (ParkCapS[1].s == ISS_ON)
451  {
452  LOG_ERROR("Cannot control light while cap is unparked.");
453  return false;
454  }
455 
456  if (enable)
457  {
458  return SetLightBoxBrightness(255);
459  }
460  else
461  {
462  return switchOffLightBox();
463  }
464 
465  return false;
466 }
467 
468 bool WandererCover::switchOffLightBox()
469 {
470  if (isSimulation())
471  {
472  setLightBoxStatusAsSwitchedOff();
473  return true;
474  }
475  char response[WANDERER_RESPONSE_SIZE];
476 
477  if (!sendCommand(TURN_OFF_LIGHT_PANEL_COMMAND, response, false))
478  return false;
479 
480  setLightBoxStatusAsSwitchedOff();
481  return true;
482 }
483 
484 void WandererCover::setLightBoxStatusAsSwitchedOff()
485 {
486  IUSaveText(&StatusT[1], "Off");
487  LightS[0].s = ISS_OFF;
488  LightS[1].s = ISS_ON;
489  LightIntensityN[0].value = 0;
490  IDSetNumber(&LightIntensityNP, nullptr);
491  IDSetSwitch(&LightSP, nullptr);
492  LOG_INFO("Light panel switched off");
493 }
494 
495 
497 {
498  if (isSimulation())
499  {
500  setLightBoxBrightnesStatusToValue(value);
501  return true;
502  }
503  char response[WANDERER_RESPONSE_SIZE];
504  char command[3] = {0};
505  snprintf(command, 3, "%03d\n", value);
506  if (!sendCommand(command, response, false))
507  return false;
508 
509  setLightBoxBrightnesStatusToValue(value);
510 
511  return true;
512 }
513 
514 bool WandererCover::setCurrentPositionToOpenPosition()
515 {
516  if (isSimulation())
517  {
518  LOG_INFO("Current position set to open position");
519  NumberOfDegreesSinceLastOpenPositionSet = 0;
520  return true;
521  }
522  char response[WANDERER_RESPONSE_SIZE];
523  if (!sendCommand(SET_CURRENT_POSITION_TO_OPEN_POSITION, response, false))
524  return false;
525 
526  NumberOfDegreesSinceLastOpenPositionSet = 0;
527 
528  return true;
529 }
530 
531 bool WandererCover::setCurrentPositionToClosedPosition()
532 {
533  int cumulative_angle_value = ((abs(NumberOfDegreesSinceLastOpenPositionSet) * 222.22) / 10) + 10000;
534 
535  if (isSimulation())
536  {
537  LOG_INFO("Current position set to closed position");
538  LOGF_INFO("Sending cumulative angle of %d", cumulative_angle_value);
539  setNumberOfStepsStatusValue(cumulative_angle_value);
540  setParkCapStatusAsClosed();
541  return true;
542  }
543  char response[WANDERER_RESPONSE_SIZE];
544  if (!sendCommand(SET_CURRENT_POSITION_TO_CLOSED_POSITION, response, false))
545  return false;
546 
547  if (!sendCommand(std::to_string(cumulative_angle_value).c_str(), response, false))
548  return false;
549 
550  setNumberOfStepsStatusValue(cumulative_angle_value);
551 
552  setParkCapStatusAsClosed();
553 
554  return true;
555 }
556 
557 void WandererCover::setLightBoxBrightnesStatusToValue(uint16_t value)
558 {
559  LightIntensityN[0].value = value;
560  IDSetNumber(&LightIntensityNP, nullptr);
561  LOGF_INFO("Brightness set to %d.", value);
562 }
563 
564 void WandererCover::setNumberOfStepsStatusValue(int value)
565 {
566  LOGF_DEBUG("Current number of steps value configured between open and closed position : %d", value);
567  NumberOfStepsBeetweenOpenAndCloseState = value;
568  // NumberOfStepsBeetweenOpenAndCloseStateT[0].text = new char[5];
569  // NumberOfStepsBeetweenOpenAndCloseStateT[0].text = (char*) std::to_string(value).c_str();
570  // IDSetText(&NumberOfStepsBeetweenOpenAndCloseStateTP, nullptr);
571 }
572 
573 bool WandererCover::sendCommand(std::string command, char *response, bool waitForAnswer)
574 {
575  int nbytes_read = 0, nbytes_written = 0, rc = -1;
576  std::string command_termination = "\n";
577  LOGF_DEBUG("CMD: %s", command.c_str());
578  if ((rc = tty_write_string(PortFD, (command + command_termination).c_str(), &nbytes_written)) != TTY_OK)
579  {
580  char errorMessage[MAXRBUF];
581  tty_error_msg(rc, errorMessage, MAXRBUF);
582  LOGF_ERROR("Serial write error: %s", errorMessage);
583  return false;
584  }
585 
586  if (waitForAnswer && (rc = tty_read_section(PortFD, response, 'A', COMMAND_WAITING_TIME, &nbytes_read)) != TTY_OK)
587  {
588  char errorMessage[MAXRBUF];
589  tty_error_msg(rc, errorMessage, MAXRBUF);
590  LOGF_ERROR("Device read error: %s", errorMessage);
591  return false;
592  }
593  LOGF_DEBUG("RESPONSE: %s", response);
594  SetTimer(150);
595  return true;
596 }
597 
598 IPState WandererCover::moveDustCap(int degrees)
599 {
600  if (degrees < -360 or degrees > 360)
601  {
602  LOGF_ERROR("Degrees must be between -360 and 360 : %d", degrees);
603  return IPS_ALERT;
604  }
605  if (isSimulation())
606  {
607  LOGF_INFO("Moving dust cap cover of %d degrees", degrees);
608  NumberOfDegreesSinceLastOpenPositionSet += degrees;
609  LOGF_INFO("Number of degrees since last open position set : %d", NumberOfDegreesSinceLastOpenPositionSet);
610  return IPS_OK;
611  }
612 
613  int stepping_offset = 100000;
614  if (degrees < 0)
615  {
616  stepping_offset = -100000;
617  }
618 
619  int command_value = (degrees * 222.22) + stepping_offset;
620 
621  char response[3];
622  if (!sendCommand(std::to_string(command_value).c_str(), response, true))
623  return IPS_ALERT;
624 
625  NumberOfDegreesSinceLastOpenPositionSet += degrees;
626  LOGF_DEBUG("Number of degrees since last open position set : %d", NumberOfDegreesSinceLastOpenPositionSet);
627  return IPS_OK;
628 }
629 
630 bool WandererCover::processConfigurationButtonSwitch(const char *dev, const char *name, ISState *states, char *names[],
631  int n)
632 {
633  if (strcmp(dev, getDeviceName()) == 0)
634  {
635  // configuration of open state clicked
636  if (!strcmp(ControlPositionPositiveDegreesConfigurationVP.name, name))
637  {
638  IUUpdateSwitch(&ControlPositionPositiveDegreesConfigurationVP, states, names, n);
639  if (ControlPositionPositiveDegreesConfigurationV[PLUS_1_DEGREE].s )
640  {
641  moveDustCap(1);
642  ControlPositionPositiveDegreesConfigurationV[PLUS_1_DEGREE].s = ISS_OFF;
643  }
644  else if (ControlPositionPositiveDegreesConfigurationV[PLUS_10_DEGREE].s == ISS_ON)
645  {
646  moveDustCap(10);
647  ControlPositionPositiveDegreesConfigurationV[PLUS_10_DEGREE].s = ISS_OFF;
648  }
649  else if (ControlPositionPositiveDegreesConfigurationV[PLUS_50_DEGREE].s == ISS_ON)
650  {
651  moveDustCap(50);
652  ControlPositionPositiveDegreesConfigurationV[PLUS_50_DEGREE].s = ISS_OFF;
653  }
654  IDSetSwitch(&ControlPositionPositiveDegreesConfigurationVP, nullptr);
655 
656  return true;
657  }
658 
659  if (!strcmp(ControlPositionNegativeDegreesConfigurationVP.name, name))
660  {
661  IUUpdateSwitch(&ControlPositionNegativeDegreesConfigurationVP, states, names, n);
662  if (ControlPositionNegativeDegreesConfigurationV[MINUS_1_DEGREE].s )
663  {
664  moveDustCap(-1);
665  ControlPositionNegativeDegreesConfigurationV[MINUS_1_DEGREE].s = ISS_OFF;
666  }
667  else if (ControlPositionNegativeDegreesConfigurationV[MINUS_10_DEGREE].s == ISS_ON)
668  {
669  moveDustCap(-10);
670  ControlPositionNegativeDegreesConfigurationV[MINUS_10_DEGREE].s = ISS_OFF;
671  }
672  else if (ControlPositionNegativeDegreesConfigurationV[MINUS_50_DEGREE].s == ISS_ON)
673  {
674  moveDustCap(-50);
675  ControlPositionNegativeDegreesConfigurationV[MINUS_50_DEGREE].s = ISS_OFF;
676  }
677  IDSetSwitch(&ControlPositionNegativeDegreesConfigurationVP, nullptr);
678 
679  return true;
680  }
681 
682  if (!strcmp(DefinePositionConfigurationVP.name, name))
683  {
684  IUUpdateSwitch(&DefinePositionConfigurationVP, states, names, n);
685  if (DefinePositionConfigurationV[SET_CURRENT_POSITION_OPEN].s == ISS_ON)
686  {
687  setCurrentPositionToOpenPosition();
688  DefinePositionConfigurationV[SET_CURRENT_POSITION_OPEN].s = ISS_OFF;
689  }
690  else if (DefinePositionConfigurationV[SET_CURRENT_POSITION_CLOSE].s == ISS_ON)
691  {
692  setCurrentPositionToClosedPosition();
693  DefinePositionConfigurationV[SET_CURRENT_POSITION_CLOSE].s = ISS_OFF;
694  }
695  IDSetSwitch(&DefinePositionConfigurationVP, nullptr);
696  return true;
697  }
698  }
699 
700  return false;
701 }
702 
703 bool WandererCover::hasWandererSentAnError(char* response)
704 {
705  const std::string response_string( response );
706  size_t found = response_string.find("Error");
707  if (found != std::string::npos)
708  return true;
709 
710  return false;
711 }
712 
713 void WandererCover::displayConfigurationMessage()
714 {
715  LOG_WARN(" - Once thesest steps are done, the dust cover will remember the park and unpark positions.");
716  LOG_WARN(" - Click on 'Set current position as close' to define the park position");
717  LOG_WARN(" - Use again the select list to move your cover panel in close position on the scope");
718  LOG_WARN(" - Click on 'Set current position as open' to define the unpark position");
719  LOG_WARN(" - Use the select controler to move your panel to the open position");
720  LOG_WARN("In order to do so, go to 'Dust cover configurtation' tab and do the following steps :");
721  LOG_WARN("Before first use, or when you change your setup, you need to configure Open and closed position first in 'Dust cover configurtation' tab.");
722 }
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
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
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
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)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
bool isSimulation() const
void syncDriverInfo()
syncDriverInfo sends the current driver information to the client.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
void initDustCapProperties(const char *deviceName, const char *groupName)
Initilize dust cap properties. It is recommended to call this function within initProperties() of you...
bool processDustCapSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process dust cap switch properties.
ISwitchVectorProperty ParkCapSP
INumberVectorProperty LightIntensityNP
bool processLightBoxNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process light box number properties.
ISwitchVectorProperty LightSP
bool processLightBoxSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process light box switch properties.
void initLightBoxProperties(const char *deviceName, const char *groupNam)
Initilize light box properties. It is recommended to call this function within initProperties() of yo...
bool processLightBoxText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process light box text properties.
void isGetLightBoxProperties(const char *deviceName)
isGetLightBoxProperties Get light box properties
Provides interface to implement controllable light box/switch device.
virtual bool SetLightBoxBrightness(uint16_t value) override
setBrightness Set light level. Must be impelemented in the child class, if supported.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool EnableLightBox(bool enable) override
EnableLightBox Turn on/off on a light box. Must be impelemented in the child class.
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState ParkCap() override
Park dust cap (close cover). Must be implemented by child.
virtual IPState UnParkCap() override
unPark dust cap (open cover). Must be implemented by child.
const char * getDefaultName() override
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
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_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_ATMOST1
Definition: indiapi.h:174
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:566
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
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
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_WARN(txt)
Definition: indilogger.h:73
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define LOG_INFO(txt)
Definition: indilogger.h:74
#define MAXRBUF
Definition: indiserver.cpp:102
@ value
the parser finished reading a JSON value
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:23613
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250
#define TAB_NAME_CONFIGURATION
#define CLOSE_COVER_COMMAND
#define HANDSHAKE_COMMAND
#define WANDERER_RESPONSE_SIZE
#define OPEN_COVER_COMMAND
#define SET_CURRENT_POSITION_TO_CLOSED_POSITION
#define COMMAND_WAITING_TIME
#define TURN_OFF_LIGHT_PANEL_COMMAND
#define SET_CURRENT_POSITION_TO_OPEN_POSITION