36 #include <sys/ioctl.h>
39 static std::unique_ptr<WandererCover> wanderercover(
new WandererCover());
43 #define WANDERER_RESPONSE_SIZE 1
44 #define COMMAND_WAITING_TIME 120
46 #define FIRST_SUPPORTED_VERSION "20220920"
48 #define TAB_NAME_CONFIGURATION "Dust cover configuration"
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"
55 # define SET_CURRENT_POSITION_TO_OPEN_POSITION "257\n"
56 # define SET_CURRENT_POSITION_TO_CLOSED_POSITION "256\n"
74 IUFillText(&StatusT[0],
"Cover",
"Cover",
nullptr);
75 IUFillText(&StatusT[1],
"Light",
"Light",
nullptr);
79 IUFillText(&FirmwareT[0],
"Version",
"Version",
nullptr);
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,
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,
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);
123 bool WandererCover::Handshake()
130 IUSaveText(&FirmwareT[0],
"Simulation version");
133 updateCoverStatus((
char*)
"0");
135 setLightBoxStatusAsSwitchedOff();
137 NumberOfStepsBeetweenOpenAndCloseState = 0;
138 setNumberOfStepsStatusValue(NumberOfStepsBeetweenOpenAndCloseState);
144 tcflush(PortFD, TCIOFLUSH);
145 int nbytes_read_name = 0, nbytes_written = 0, rc = -1;
152 LOGF_ERROR(
"Serial write error: %s", errorMessage);
160 LOGF_ERROR(
"Device read error: %s", errorMessage);
163 name[nbytes_read_name - 1] =
'\0';
166 int nbytes_read_version = 0;
167 char version[64] = {0};
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");
178 displayConfigurationMessage();
179 version[nbytes_read_version - 1] =
'\0';
186 char cover_state[64] = {0};
187 int nbytes_read_cover_state = 0;
193 LOGF_ERROR(
"Device read error: %s", errorMessage);
196 cover_state[nbytes_read_cover_state - 1] =
'\0';
197 LOGF_INFO(
"Cover state : %s", cover_state);
198 updateCoverStatus(cover_state);
201 char number_of_steps[64] = {0};
202 int nbytes_read_number_of_steps = 0;
208 LOGF_ERROR(
"Device read error: %s", errorMessage);
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)
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.",
219 setNumberOfStepsStatusValue(NumberOfStepsBeetweenOpenAndCloseState);
221 setLightBoxStatusAsSwitchedOff();
223 LOGF_INFO(
"Handshake successful:%s", name);
224 tcflush(PortFD, TCIOFLUSH);
228 void WandererCover::updateCoverStatus(
char* res)
230 if (strcmp(res,
"0") == 0)
232 setParkCapStatusAsClosed();
234 else if (strcmp(res,
"1") == 0)
236 setParkCapStatusAsOpen();
238 else if (strcmp(res,
"255") == 0)
240 LOGF_INFO(
"No cover status information available. You should first open/close the cover.",
"");
291 return "Wanderer Cover v3";
326 if (processConfigurationButtonSwitch(dev, name, states, names, n))
347 bool WandererCover::getStartupData()
371 if (NumberOfStepsBeetweenOpenAndCloseState == 0)
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.",
380 setParkCapStatusAsClosed();
389 if (hasWandererSentAnError(response))
391 LOG_ERROR(
"You need to configure Open and closed position first in 'Dust cover configuration' tab.");
394 setParkCapStatusAsClosed();
399 void WandererCover::setParkCapStatusAsClosed()
411 if (NumberOfStepsBeetweenOpenAndCloseState == 0)
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.");
419 setParkCapStatusAsOpen();
428 if (hasWandererSentAnError(response))
430 displayConfigurationMessage();
434 setParkCapStatusAsOpen();
438 void WandererCover::setParkCapStatusAsOpen()
452 LOG_ERROR(
"Cannot control light while cap is unparked.");
462 return switchOffLightBox();
468 bool WandererCover::switchOffLightBox()
472 setLightBoxStatusAsSwitchedOff();
480 setLightBoxStatusAsSwitchedOff();
484 void WandererCover::setLightBoxStatusAsSwitchedOff()
492 LOG_INFO(
"Light panel switched off");
500 setLightBoxBrightnesStatusToValue(value);
504 char command[3] = {0};
505 snprintf(command, 3,
"%03d\n", value);
506 if (!sendCommand(command, response,
false))
509 setLightBoxBrightnesStatusToValue(value);
514 bool WandererCover::setCurrentPositionToOpenPosition()
518 LOG_INFO(
"Current position set to open position");
519 NumberOfDegreesSinceLastOpenPositionSet = 0;
526 NumberOfDegreesSinceLastOpenPositionSet = 0;
531 bool WandererCover::setCurrentPositionToClosedPosition()
533 int cumulative_angle_value = ((abs(NumberOfDegreesSinceLastOpenPositionSet) * 222.22) / 10) + 10000;
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();
547 if (!sendCommand(
std::to_string(cumulative_angle_value).c_str(), response,
false))
550 setNumberOfStepsStatusValue(cumulative_angle_value);
552 setParkCapStatusAsClosed();
557 void WandererCover::setLightBoxBrightnesStatusToValue(uint16_t value)
561 LOGF_INFO(
"Brightness set to %d.", value);
564 void WandererCover::setNumberOfStepsStatusValue(
int value)
566 LOGF_DEBUG(
"Current number of steps value configured between open and closed position : %d", value);
567 NumberOfStepsBeetweenOpenAndCloseState =
value;
573 bool WandererCover::sendCommand(std::string command,
char *response,
bool waitForAnswer)
575 int nbytes_read = 0, nbytes_written = 0, rc = -1;
576 std::string command_termination =
"\n";
582 LOGF_ERROR(
"Serial write error: %s", errorMessage);
590 LOGF_ERROR(
"Device read error: %s", errorMessage);
598 IPState WandererCover::moveDustCap(
int degrees)
600 if (degrees < -360 or degrees > 360)
602 LOGF_ERROR(
"Degrees must be between -360 and 360 : %d", degrees);
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);
613 int stepping_offset = 100000;
616 stepping_offset = -100000;
619 int command_value = (degrees * 222.22) + stepping_offset;
622 if (!sendCommand(
std::to_string(command_value).c_str(), response,
true))
625 NumberOfDegreesSinceLastOpenPositionSet += degrees;
626 LOGF_DEBUG(
"Number of degrees since last open position set : %d", NumberOfDegreesSinceLastOpenPositionSet);
630 bool WandererCover::processConfigurationButtonSwitch(
const char *dev,
const char *name,
ISState *states,
char *names[],
636 if (!strcmp(ControlPositionPositiveDegreesConfigurationVP.
name, name))
638 IUUpdateSwitch(&ControlPositionPositiveDegreesConfigurationVP, states, names, n);
639 if (ControlPositionPositiveDegreesConfigurationV[PLUS_1_DEGREE].s )
642 ControlPositionPositiveDegreesConfigurationV[PLUS_1_DEGREE].s =
ISS_OFF;
644 else if (ControlPositionPositiveDegreesConfigurationV[PLUS_10_DEGREE].s ==
ISS_ON)
647 ControlPositionPositiveDegreesConfigurationV[PLUS_10_DEGREE].s =
ISS_OFF;
649 else if (ControlPositionPositiveDegreesConfigurationV[PLUS_50_DEGREE].s ==
ISS_ON)
652 ControlPositionPositiveDegreesConfigurationV[PLUS_50_DEGREE].s =
ISS_OFF;
654 IDSetSwitch(&ControlPositionPositiveDegreesConfigurationVP,
nullptr);
659 if (!strcmp(ControlPositionNegativeDegreesConfigurationVP.
name, name))
661 IUUpdateSwitch(&ControlPositionNegativeDegreesConfigurationVP, states, names, n);
662 if (ControlPositionNegativeDegreesConfigurationV[MINUS_1_DEGREE].s )
665 ControlPositionNegativeDegreesConfigurationV[MINUS_1_DEGREE].s =
ISS_OFF;
667 else if (ControlPositionNegativeDegreesConfigurationV[MINUS_10_DEGREE].s ==
ISS_ON)
670 ControlPositionNegativeDegreesConfigurationV[MINUS_10_DEGREE].s =
ISS_OFF;
672 else if (ControlPositionNegativeDegreesConfigurationV[MINUS_50_DEGREE].s ==
ISS_ON)
675 ControlPositionNegativeDegreesConfigurationV[MINUS_50_DEGREE].s =
ISS_OFF;
677 IDSetSwitch(&ControlPositionNegativeDegreesConfigurationVP,
nullptr);
682 if (!strcmp(DefinePositionConfigurationVP.
name, name))
685 if (DefinePositionConfigurationV[SET_CURRENT_POSITION_OPEN].s ==
ISS_ON)
687 setCurrentPositionToOpenPosition();
688 DefinePositionConfigurationV[SET_CURRENT_POSITION_OPEN].s =
ISS_OFF;
690 else if (DefinePositionConfigurationV[SET_CURRENT_POSITION_CLOSE].s ==
ISS_ON)
692 setCurrentPositionToClosedPosition();
693 DefinePositionConfigurationV[SET_CURRENT_POSITION_CLOSE].s =
ISS_OFF;
695 IDSetSwitch(&DefinePositionConfigurationVP,
nullptr);
703 bool WandererCover::hasWandererSentAnError(
char* response)
705 const std::string response_string( response );
706 size_t found = response_string.find(
"Error");
707 if (found != std::string::npos)
713 void WandererCover::displayConfigurationMessage()
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.");
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...
const char * getDeviceName() const
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 snoopLightBox(XMLEle *root)
INumber LightIntensityN[1]
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.
bool updateLightBoxProperties()
bool saveLightBoxConfigItems(FILE *fp)
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.
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Implementations for common driver routines.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
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.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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.
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.
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.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
@ 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
#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