Instrument Neutral Distributed Interface INDI  2.0.2
Excalibur.cpp
Go to the documentation of this file.
1 
2 #include "Excalibur.h"
3 
4 #include "indicom.h"
6 
7 #include <cerrno>
8 #include <cstring>
9 #include <memory>
10 #include <termios.h>
11 #include <unistd.h>
12 #include <inttypes.h>
13 #include <sys/ioctl.h>
14 #include <math.h>
15 #define CLOSE_CMD "S1#"
16 #define OPEN_CMD "S0#"
17 
18 static std::unique_ptr<Excalibur> flatmaster(new Excalibur());
19 
20 
22 {
23  setVersion(1, 0);
24 }
25 
27 {
29 
30  IUFillText(&StatusT[0], "Cover", "Cover", nullptr);
31  IUFillText(&StatusT[1], "Light", "Light", nullptr);
32  IUFillTextVector(&StatusTP, StatusT, 2, getDeviceName(), "Status", "Status", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
33 
36 
38 
39  LightIntensityN[0].min = 0;
40  LightIntensityN[0].max = 3000;
41  LightIntensityN[0].step = 1;
42 
44 
45  serialConnection = new Connection::Serial(this);
47  serialConnection->registerHandshake([&]()
48  {
49  return Ack();
50  });
51 
52 
53  registerConnection(serialConnection);
54  return true;
55 }
56 
57 
59 {
61 
62  if (isConnected())
63  {
67  defineProperty(&StatusTP);
68 
69  }
70  else
71  {
75  deleteProperty(StatusTP.name);
76 
77  }
78 
80  return true;
81 }
82 
84 {
85  return "RBF Excalibur";
86 }
87 
88 
89 
90 bool Excalibur::Ack()
91 {
92  PortFD = serialConnection->getPortFD();
93 
94  char response[16] = {0};
95  if(sendCommand("#", response))
96  {
97  if(strstr("FLAT.FLAP!#", response) != nullptr)
98  {
99  LightS[1].s = ISS_ON;
100  LightS[0].s = ISS_OFF;
101  IDSetSwitch(&LightSP, nullptr);
102  deviceStatus();
103  return true;
104 
105  }
106  }
107  else
108  {
109  LOG_ERROR("Ack failed.");
110  return false;
111  }
112 
113  return false;
114 }
115 
116 bool Excalibur::EnableLightBox(bool enable)
117 {
118  char response[20]= {0};
119  char cmd[16] = {0};
120  if (!enable){
121  snprintf(cmd, 16, "L%d##", 0);
122 
123  sendCommand(cmd,response);
124  IUSaveText(&StatusT[1], "Off");
125  IDSetText(&StatusTP, nullptr);
126  return true;
127 
128 
129 
130  }
131  else
132  {
133 
134  snprintf(cmd, 16, "L%d##", (int)LightIntensityN[0].value);
135 
136  sendCommand(cmd,response);
137  IUSaveText(&StatusT[1], "On");
138  IDSetText(&StatusTP, nullptr);
139  return true;
140 
141 
142  }
143 
144 
145  return false;
146 }
147 
149 {
150  if(LightS[FLAT_LIGHT_ON].s != ISS_ON)
151  {
152  LOG_ERROR("You must set On the Flat Light first.");
153  return false;
154  }
155  if( ParkCapS[0].s != ISS_ON)
156  {
157  LOG_ERROR("You must Park eXcalibur first.");
158  return false;
159  }
160 
161  //char response[20] = {0};
162  char cmd[DRIVER_RES] = {0};
163 
164  snprintf(cmd, 30, "L%d##", value);
165  sendCommand(cmd);
166  return true;
167 
168 
169 
170 }
172 {
173 
174  sendCommand("S1#");
175 
176 
177  //IUSaveText(&StatusT[0], "Closed");
178  //IUSaveText(&StatusT[1], "On");
180  ParkCapS[0].s = ISS_ON;
181  ParkCapSP.s = IPS_OK;
182  LOG_INFO("Cover closed.");
183  IDSetSwitch(&ParkCapSP, nullptr);
184  IDSetText(&StatusTP, nullptr);
185  return IPS_OK;
186 }
187 
189 {
190 
191  sendCommand("S0#");
192 
193  // Set cover status to random value outside of range to force it to refresh
194  //IUSaveText(&StatusT[0], "Open");
195  IUSaveText(&StatusT[1], "Off");
197  ParkCapS[1].s = ISS_ON;
198  ParkCapSP.s = IPS_OK;
199  LOG_INFO("Cover open.");
200  IDSetSwitch(&ParkCapSP, nullptr);
201  IDSetText(&StatusTP, nullptr);
202  return IPS_OK;
203 }
205 {
206  if (!isConnected())
207  return;
208 
209  deviceStatus();
210 
211  // parking or unparking timed out, try again
212  if (ParkCapSP.s == IPS_BUSY && !strcmp(StatusT[0].text, "Timed out"))
213  {
214  if (ParkCapS[0].s == ISS_ON)
215  ParkCap();
216  else
217  UnParkCap();
218  }
219 
221 }
222 
223 bool Excalibur::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
224 {
225  if (processLightBoxNumber(dev, name, values, names, n))
226  return true;
227 
228  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
229 }
230 
231 bool Excalibur::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
232 {
233  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
234  {
235  if (processLightBoxText(dev, name, texts, names, n))
236  return true;
237  }
238 
239  return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
240 }
241 
242 bool Excalibur::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
243 {
244  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
245  {
246  if (processDustCapSwitch(dev, name, states, names, n))
247  return true;
248  if (processLightBoxSwitch(dev, name, states, names, n))
249  return true;
250  }
251 
252  return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
253 }
254 
256 {
257  snoopLightBox(root);
258 
260 }
261 
263 {
265 
266  return saveLightBoxConfigItems(fp);
267 }
268 
269 bool Excalibur::sendCommand(const char *command, char *res)
270 {
271  int nbytes_written = 0, nbytes_read = 0, rc = -1;
272  char errstr[MAXRBUF];
273 
274  char cmd[20] = {0};
275  snprintf(cmd, 20, "%s", command);
276 
277  LOGF_DEBUG("CMD <%#02X>", cmd[0]);
278 
279  tcflush(PortFD, TCIOFLUSH);
280 
281  if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
282  {
283  char errstr[MAXRBUF] = {0};
284  tty_error_msg(rc, errstr, MAXRBUF);
285  LOGF_ERROR("Serial write error: %s.", errstr);
286  return false;
287  }
288  if (res == nullptr)
289  return true;
290 
291  if ((rc = tty_read_section(PortFD, res, DRIVER_DEL, 5, &nbytes_read)) != TTY_OK)
292  {
293  tty_error_msg(rc, errstr, MAXRBUF);
294  LOGF_ERROR("command: %s error: %s.", cmd, errstr);
295  return false;
296  }
297 
298  // Remove the #
299  res[nbytes_read - 1] = 0;
300 
301  LOGF_DEBUG("RES <%s>", res);
302 
303  tcflush(PortFD, TCIOFLUSH);
304 
305  return true;
306 }
307 void Excalibur::deviceStatus()
308 {
309  char res[DRIVER_RES] = {0};
310 
311  sendCommand("O#", res);
312 
313  int32_t pos;
314  int rc = sscanf(res, "%d#", &pos);
315 
316  if (rc > 0)
317  {
318  LightIntensityN[0].value = pos;
319  IDSetNumber(&LightIntensityNP, nullptr);
320  }
321  if(LightIntensityN[0].value>0)
322  {
323  IUSaveText(&StatusT[1], "On");
324  if (LightS[1].s == ISS_ON)
325  {
326  LightS[0].s = ISS_ON;
327  LightS[1].s = ISS_OFF;
328  IDSetSwitch(&LightSP, nullptr);
329  }
330 
331  }
332  else
333  {
334  IUSaveText(&StatusT[1], "Off");
335 
336  }
337 
338 
339  sendCommand("P#", res);
340 
341  int32_t pos2;
342  sscanf(res, "%d#", &pos2);
343 
344 
345  if(pos2<=0){
346  IUSaveText(&StatusT[0], "Closed");
347  if ( ParkCapS[0].s == ISS_OFF)
348  {
349  ParkCapS[0].s = ISS_ON;
350  IDSetSwitch(&LightSP, nullptr);
351  }
352  }
353  else
354  {
355  IUSaveText(&StatusT[0], "Open");
356  if ( ParkCapS[1].s == ISS_OFF)
357  {
358  ParkCapS[1].s = ISS_ON;
359  IUSaveText(&StatusT[1], "Off");
360  IDSetSwitch(&LightSP, nullptr);
361  }
362 
363  }
364  IDSetText(&StatusTP, nullptr);
365 
366 }
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...
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: Excalibur.cpp:262
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: Excalibur.cpp:255
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: Excalibur.cpp:58
virtual bool EnableLightBox(bool enable) override
EnableLightBox Turn on/off on a light box. Must be impelemented in the child class.
Definition: Excalibur.cpp:116
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: Excalibur.cpp:26
virtual IPState ParkCap() override
Park dust cap (close cover). Must be implemented by child.
Definition: Excalibur.cpp:171
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: Excalibur.cpp:223
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: Excalibur.cpp:204
virtual bool SetLightBoxBrightness(uint16_t value) override
setBrightness Set light level. Must be impelemented in the child class, if supported.
Definition: Excalibur.cpp:148
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: Excalibur.cpp:242
virtual IPState UnParkCap() override
unPark dust cap (open cover). Must be implemented by child.
Definition: Excalibur.cpp:188
const char * getDefaultName() override
Definition: Excalibur.cpp:83
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: Excalibur.cpp:231
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 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...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
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.
Provides interface to implement controllable light box/switch device.
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_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
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 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 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_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
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250