Instrument Neutral Distributed Interface INDI  2.0.2
abstractbaseclient.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2016 Jasem Mutlaq. All rights reserved.
3  Copyright(c) 2022 Pawel Soja <kernel32.pl@gmail.com>
4 
5  INDI Qt Client
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for 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 
22 #include "abstractbaseclient.h"
23 #include "abstractbaseclient_p.h"
24 
25 #include "basedevice.h"
26 #include "basedevice_p.h"
27 
28 #include "indiuserio.h"
29 #include "locale_compat.h"
30 #include "indistandardproperty.h"
31 
32 #if defined(_MSC_VER)
33 #define snprintf _snprintf
34 #pragma warning(push)
36 #pragma warning(disable : 4996)
37 #endif
38 
39 namespace INDI
40 {
41 
43 
44 // AbstractBaseClientPrivate
45 
47  : parent(parent)
48 {
49  io.write = [](void *user, const void * ptr, size_t count) -> ssize_t
50  {
51  auto self = static_cast<AbstractBaseClientPrivate *>(user);
52  return self->sendData(ptr, count);
53  };
54 
55  io.vprintf = [](void *user, const char * format, va_list ap) -> int
56  {
57  auto self = static_cast<AbstractBaseClientPrivate *>(user);
58  char message[MAXRBUF];
59  vsnprintf(message, MAXRBUF, format, ap);
60  return int(self->sendData(message, strlen(message)));
61  };
62 }
63 
65 {
67  blobModes.clear();
68 }
69 
71 {
72  // Ignore echoed newXXX
73  if (root.tagName().find("new") == 0)
74  {
75  return 0;
76  }
77 
78  if (root.tagName() == "pingRequest")
79  {
80  parent->sendPingReply(root.getAttribute("uid"));
81  return 0;
82  }
83 
84  if (root.tagName() == "pingReply")
85  {
86  parent->newPingReply(root.getAttribute("uid").toString());
87  return 0;
88  }
89 
90  if (root.tagName() == "message")
91  {
92  return messageCmd(root, errmsg);
93  }
94 
95  if (root.tagName() == "delProperty")
96  {
97  return delPropertyCmd(root, errmsg);
98  }
99 
100  // Just ignore any getProperties we might get
101  if (root.tagName() == "getProperties")
102  {
104  }
105 
106  // If device is set to BLOB_ONLY, we ignore everything else
107  // not related to blobs
108  if (
109  parent->getBLOBMode(root.getAttribute("device")) == B_ONLY &&
110  root.tagName() != "defBLOBVector" &&
111  root.tagName() != "setBLOBVector"
112  )
113  {
114  return 0;
115  }
116 
117  return watchDevice.processXml(root, errmsg, [this] // create new device if nessesery
118  {
120  device.setMediator(parent);
121  return device;
122  });
123 }
124 
125 int AbstractBaseClientPrivate::deleteDevice(const char *devName, char *errmsg)
126 {
127  if (auto device = watchDevice.getDeviceByName(devName))
128  {
129  device.detach();
131  return 0;
132  }
133  snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
134  return INDI_DEVICE_NOT_FOUND;
135 }
136 
137 /* delete the property in the given device, including widgets and data structs.
138  * when last property is deleted, delete the device too.
139  * if no property name attribute at all, delete the whole device regardless.
140  * return 0 if ok, else -1 with reason in errmsg[].
141  */
143 {
144  /* dig out device and optional property name */
145  BaseDevice dp = watchDevice.getDeviceByName(root.getAttribute("device"));
146 
147  if (!dp.isValid())
148  return INDI_DEVICE_NOT_FOUND;
149 
150  dp.checkMessage(root.handle());
151 
152  const auto propertyName = root.getAttribute("name");
153 
154  // Delete the whole device if propertyName does not exists
155  if (!propertyName.isValid())
156  {
157  return deleteDevice(dp.getDeviceName(), errmsg);
158  }
159 
160  // Delete property if it exists
161  if (auto property = dp.getProperty(propertyName))
162  {
163  if (sConnected)
164  {
165  dp.d_ptr->mediateRemoveProperty(property);
166  }
167  return dp.removeProperty(propertyName, errmsg);
168  }
169 
170  // Silently ignore B_ONLY clients.
171  if (blobModes.empty() || blobModes.front().blobMode == B_ONLY)
172  return 0;
173  snprintf(errmsg, MAXRBUF, "Cannot delete property %s as it is not defined yet. Check driver.", propertyName.toCString());
174  return -1;
175 }
176 
177 /* a general message command received from the device.
178  * return 0 if ok, else -1 with reason in errmsg[].
179  */
181 {
182  INDI_UNUSED(errmsg);
183 
184  BaseDevice dp = watchDevice.getDeviceByName(root.getAttribute("device"));
185 
186  if (dp.isValid())
187  {
188  dp.checkMessage(root.handle());
189  return 0;
190  }
191 
192  char msgBuffer[MAXRBUF];
193 
194  auto timestamp = root.getAttribute("timestamp");
195  auto message = root.getAttribute("message");
196 
197  if (!message.isValid())
198  {
199  strncpy(errmsg, "No message content found.", MAXRBUF);
200  return -1;
201  }
202 
203  if (timestamp.isValid())
204  {
205  snprintf(msgBuffer, MAXRBUF, "%s: %s", timestamp.toCString(), message.toCString());
206  }
207  else
208  {
209  char ts[32];
210  struct tm *tp;
211  time_t t;
212  time(&t);
213  tp = gmtime(&t);
214  strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
215  snprintf(msgBuffer, MAXRBUF, "%s: %s", ts, message.toCString());
216  }
217 
218  parent->newUniversalMessage(msgBuffer);
219 
220  return 0;
221 }
222 
224 {
225  if (watchDevice.isEmpty())
226  {
227  IUUserIOGetProperties(&io, this, nullptr, nullptr);
228  if (verbose)
229  IUUserIOGetProperties(userio_file(), stderr, nullptr, nullptr);
230  }
231  else
232  {
233  for (const auto &deviceInfo : watchDevice /* first: device name, second: device info */)
234  {
235  // If there are no specific properties to watch, we watch the complete device
236  if (deviceInfo.second.properties.size() == 0)
237  {
238  IUUserIOGetProperties(&io, this, deviceInfo.first.c_str(), nullptr);
239  if (verbose)
240  IUUserIOGetProperties(userio_file(), stderr, deviceInfo.first.c_str(), nullptr);
241  }
242  else
243  {
244  for (const auto &oneProperty : deviceInfo.second.properties)
245  {
246  IUUserIOGetProperties(&io, this, deviceInfo.first.c_str(), oneProperty.c_str());
247  if (verbose)
248  IUUserIOGetProperties(userio_file(), stderr, deviceInfo.first.c_str(), oneProperty.c_str());
249  }
250  }
251  }
252  }
253 }
254 
255 
256 void AbstractBaseClientPrivate::setDriverConnection(bool status, const char *deviceName)
257 {
258  BaseDevice drv = parent->getDevice(deviceName);
259 
260  if (!drv.isValid())
261  {
262  IDLog("BaseClientQt: Error. Unable to find driver %s\n", deviceName);
263  return;
264  }
265 
266  auto drv_connection = drv.getSwitch(SP::CONNECTION);
267 
268  if (!drv_connection.isValid())
269  return;
270 
271  // If we need to connect
272  if (status)
273  {
274  // If there is no need to do anything, i.e. already connected.
275  if (drv_connection[0].getState() == ISS_ON)
276  return;
277 
278  drv_connection.reset();
279  drv_connection.setState(IPS_BUSY);
280  drv_connection[0].setState(ISS_ON);
281  drv_connection[1].setState(ISS_OFF);
282 
283  parent->sendNewSwitch(drv_connection);
284  }
285  else
286  {
287  // If there is no need to do anything, i.e. already disconnected.
288  if (drv_connection[1].getState() == ISS_ON)
289  return;
290 
291  drv_connection.reset();
292  drv_connection.setState(IPS_BUSY);
293  drv_connection[0].setState(ISS_OFF);
294  drv_connection[1].setState(ISS_ON);
295 
296  parent->sendNewSwitch(drv_connection);
297  }
298 }
299 
300 BLOBMode *AbstractBaseClientPrivate::findBLOBMode(const std::string &device, const std::string &property)
301 {
302  for (auto &blob : blobModes)
303  {
304  if (blob.device == device && (property.empty() || blob.property == property))
305  return &blob;
306  }
307 
308  return nullptr;
309 }
310 
311 // AbstractBaseClient
312 
313 AbstractBaseClient::AbstractBaseClient(std::unique_ptr<AbstractBaseClientPrivate> &&d)
314  : d_ptr_indi(std::move(d))
315 { }
316 
318 { }
319 
320 void AbstractBaseClient::setServer(const char *hostname, unsigned int port)
321 {
322  D_PTR(AbstractBaseClient);
323  d->cServer = hostname;
324  d->cPort = port;
325 }
326 
327 const char *AbstractBaseClient::getHost() const
328 {
329  D_PTR(const AbstractBaseClient);
330  return d->cServer.c_str();
331 }
332 
334 {
335  D_PTR(const AbstractBaseClient);
336  return d->cPort;
337 }
338 
340 {
341  D_PTR(const AbstractBaseClient);
342  return d->sConnected;
343 }
344 
345 void AbstractBaseClient::setConnectionTimeout(uint32_t seconds, uint32_t microseconds)
346 {
347  D_PTR(AbstractBaseClient);
348  d->timeout_sec = seconds;
349  d->timeout_us = microseconds;
350 }
351 
353 {
354  D_PTR(AbstractBaseClient);
355  d->verbose = enable;
356 }
357 
359 {
360  D_PTR(const AbstractBaseClient);
361  return d->verbose;
362 }
363 
364 void AbstractBaseClient::watchDevice(const char *deviceName)
365 {
366  D_PTR(AbstractBaseClient);
367  d->watchDevice.watchDevice(deviceName);
368 }
369 
370 void AbstractBaseClient::watchDevice(const char *deviceName, const std::function<void (BaseDevice)> &callback)
371 {
372  D_PTR(AbstractBaseClient);
373  d->watchDevice.watchDevice(deviceName, callback);
374 }
375 
376 void AbstractBaseClient::watchProperty(const char *deviceName, const char *propertyName)
377 {
378  D_PTR(AbstractBaseClient);
379  d->watchDevice.watchProperty(deviceName, propertyName);
380 }
381 
382 void AbstractBaseClient::connectDevice(const char *deviceName)
383 {
384  D_PTR(AbstractBaseClient);
385  d->setDriverConnection(true, deviceName);
386 }
387 
388 void AbstractBaseClient::disconnectDevice(const char *deviceName)
389 {
390  D_PTR(AbstractBaseClient);
391  d->setDriverConnection(false, deviceName);
392 }
393 
395 {
396  D_PTR(AbstractBaseClient);
397  return d->watchDevice.getDeviceByName(deviceName);
398 }
399 
400 std::vector<BaseDevice> AbstractBaseClient::getDevices() const
401 {
402  D_PTR(const AbstractBaseClient);
403  return d->watchDevice.getDevices();
404 }
405 
406 bool AbstractBaseClient::getDevices(std::vector<BaseDevice> &deviceList, uint16_t driverInterface )
407 {
408  D_PTR(AbstractBaseClient);
409  for (auto &it : d->watchDevice)
410  {
411  if (it.second.device.getDriverInterface() & driverInterface)
412  deviceList.push_back(it.second.device);
413  }
414 
415  return (deviceList.size() > 0);
416 }
417 
418 
419 void AbstractBaseClient::setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop)
420 {
421  D_PTR(AbstractBaseClient);
422  if (!dev[0])
423  return;
424 
425  auto *bMode = d->findBLOBMode(std::string(dev), prop ? std::string(prop) : std::string());
426 
427  if (bMode == nullptr)
428  {
429  BLOBMode newMode;
430  newMode.device = std::string(dev);
431  newMode.property = (prop ? std::string(prop) : std::string());
432  newMode.blobMode = blobH;
433  d->blobModes.push_back(std::move(newMode));
434  }
435  else
436  {
437  // If nothing changed, nothing to to do
438  if (bMode->blobMode == blobH)
439  return;
440 
441  bMode->blobMode = blobH;
442  }
443 
444  IUUserIOEnableBLOB(&d->io, d, dev, prop, blobH);
445 }
446 
447 BLOBHandling AbstractBaseClient::getBLOBMode(const char *dev, const char *prop)
448 {
449  D_PTR(AbstractBaseClient);
450  BLOBHandling bHandle = B_ALSO;
451 
452  auto *bMode = d->findBLOBMode(dev, (prop ? std::string(prop) : std::string()));
453 
454  if (bMode)
455  bHandle = bMode->blobMode;
456 
457  return bHandle;
458 }
459 
461 {
462  D_PTR(AbstractBaseClient);
463  pp.setState(IPS_BUSY);
464  // #PS: TODO more generic
465  switch (pp.getType())
466  {
467  case INDI_NUMBER:
468  IUUserIONewNumber(&d->io, d, pp.getNumber()->cast());
469  break;
470  case INDI_SWITCH:
471  IUUserIONewSwitch(&d->io, d, pp.getSwitch()->cast());
472  break;
473  case INDI_TEXT:
474  IUUserIONewText(&d->io, d, pp.getText()->cast());
475  break;
476  case INDI_LIGHT:
477  IDLog("Light type is not supported to send\n");
478  break;
479  case INDI_BLOB:
480  IUUserIONewBLOB(&d->io, d, pp.getBLOB()->cast());
481  break;
482  case INDI_UNKNOWN:
483  IDLog("Unknown type of property to send\n");
484  break;
485  }
486 }
487 
489 {
490  D_PTR(AbstractBaseClient);
491  AutoCNumeric locale;
492 
493  pp.setState(IPS_BUSY);
494  IUUserIONewText(&d->io, d, pp.getText()->cast());
495 }
496 
497 void AbstractBaseClient::sendNewText(const char *deviceName, const char *propertyName, const char *elementName,
498  const char *text)
499 {
500  auto tvp = getDevice(deviceName).getText(propertyName);
501 
502  if (!tvp.isValid())
503  return;
504 
505  auto tp = tvp.findWidgetByName(elementName);
506 
507  if (!tp)
508  return;
509 
510  tp->setText(text);
511 
512  sendNewText(tvp);
513 }
514 
516 {
517  D_PTR(AbstractBaseClient);
518  AutoCNumeric locale;
519  pp.setState(IPS_BUSY);
520  IUUserIONewNumber(&d->io, d, pp.getNumber()->cast());
521 }
522 
523 void AbstractBaseClient::sendNewNumber(const char *deviceName, const char *propertyName, const char *elementName,
524  double value)
525 {
526  auto nvp = getDevice(deviceName).getNumber(propertyName);
527 
528  if (!nvp.isValid())
529  return;
530 
531  auto np = nvp.findWidgetByName(elementName);
532 
533  if (!np)
534  return;
535 
536  np->setValue(value);
537 
538  sendNewNumber(nvp);
539 }
540 
542 {
543  D_PTR(AbstractBaseClient);
544  pp.setState(IPS_BUSY);
545  IUUserIONewSwitch(&d->io, d, pp.getSwitch()->cast());
546 }
547 
548 void AbstractBaseClient::sendNewSwitch(const char *deviceName, const char *propertyName, const char *elementName)
549 {
550  auto svp = getDevice(deviceName).getSwitch(propertyName);
551 
552  if (!svp.isValid())
553  return;
554 
555  auto sp = svp.findWidgetByName(elementName);
556 
557  if (!sp)
558  return;
559 
560  sp->setState(ISS_ON);
561 
562  sendNewSwitch(svp);
563 }
564 
565 void AbstractBaseClient::startBlob(const char *devName, const char *propName, const char *timestamp)
566 {
567  D_PTR(AbstractBaseClient);
568  IUUserIONewBLOBStart(&d->io, d, devName, propName, timestamp);
569 }
570 
572 {
573  D_PTR(AbstractBaseClient);
575  &d->io, d,
576  blob->getName(), blob->getSize(), blob->getBlobLen(), blob->getBlob(), blob->getFormat()
577  );
578 }
579 
581 {
583 }
584 
585 void AbstractBaseClient::sendOneBlob(const char *blobName, unsigned int blobSize, const char *blobFormat,
586  void *blobBuffer)
587 {
588  D_PTR(AbstractBaseClient);
590  &d->io, d,
591  blobName, blobSize, blobSize, blobBuffer, blobFormat
592  );
593 }
594 
596 {
597  D_PTR(AbstractBaseClient);
598  IUUserIONewBLOBFinish(&d->io, d);
599 }
600 
601 void AbstractBaseClient::sendPingRequest(const char * uuid)
602 {
603  D_PTR(AbstractBaseClient);
604  IUUserIOPingRequest(&d->io, d, uuid);
605 }
606 
607 void AbstractBaseClient::sendPingReply(const char * uuid)
608 {
609  D_PTR(AbstractBaseClient);
610  IUUserIOPingReply(&d->io, d, uuid);
611 }
612 
613 void AbstractBaseClient::newPingReply(std::string uid)
614 {
615  IDLog("Ping reply %s\n", uid.c_str());
616 }
617 
619 {
620  INDI_UNUSED(message);
621  // Do not log message to stderr, let child decide what to do with it.
622  //IDLog("%s\n", message.c_str());
623 }
624 
625 }
626 
627 #if defined(_MSC_VER)
628 #undef snprintf
629 #pragma warning(pop)
630 #endif
hid_device * device
int dispatchCommand(const INDI::LilXmlElement &root, char *errmsg)
Dispatch command received from INDI server to respective devices handled by the client.
int messageCmd(const INDI::LilXmlElement &root, char *errmsg)
AbstractBaseClientPrivate(AbstractBaseClient *parent)
void setDriverConnection(bool status, const char *deviceName)
Connect/Disconnect to INDI driver.
int deleteDevice(const char *devName, char *errmsg)
Remove device.
int delPropertyCmd(const INDI::LilXmlElement &root, char *errmsg)
Delete property command.
virtual ssize_t sendData(const void *data, size_t size)=0
BLOBMode * findBLOBMode(const std::string &device, const std::string &property)
int getPort() const
Get the port number.
void setServer(const char *hostname, unsigned int port)
Set the server host name and port.
bool isVerbose() const
isVerbose Is client in verbose mode?
INDI::BaseDevice getDevice(const char *deviceName)
virtual void newUniversalMessage(std::string message)
newUniversalMessage Universal messages are sent from INDI server without a specific device....
void sendNewSwitch(INDI::Property pp)
Send new Switch command to server.
void setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop=nullptr)
Set Binary Large Object policy mode.
void watchProperty(const char *deviceName, const char *propertyName)
watchProperties Add a property to the watch list. When communicating with INDI server.
void sendNewProperty(INDI::Property pp)
Send new Property command to server.
void setConnectionTimeout(uint32_t seconds, uint32_t microseconds)
setConnectionTimeout Set connection timeout. By default it is 3 seconds.
void finishBlob()
Send closing tag for BLOB command to server.
void disconnectDevice(const char *deviceName)
Disconnect INDI driver.
void setVerbose(bool enable)
setVerbose Set verbose mode
void sendPingReply(const char *uid)
Send a ping reply for the given uuid.
void sendOneBlob(IBLOB *bp)
Send ONE blob content to server. The BLOB data in raw binary format and will be converted to base64 a...
virtual void newPingReply(std::string uid)
pingReply are sent by the server on response to pingReply (see above).
bool isServerConnected() const
Get status of the connection.
void sendPingRequest(const char *uid)
Send one ping request, the server will answer back with the same uuid.
void connectDevice(const char *deviceName)
Disconnect INDI driver.
void watchDevice(const char *deviceName)
Add a device to the watch list.
const char * getHost() const
Get the server host name.
std::vector< INDI::BaseDevice > getDevices() const
void sendNewNumber(INDI::Property pp)
Send new Number command to server.
BLOBHandling getBLOBMode(const char *dev, const char *prop=nullptr)
getBLOBMode Get Binary Large Object policy mode IF set previously by setBLOBMode
void sendNewText(INDI::Property pp)
Send new Text command to server.
void startBlob(const char *devName, const char *propName, const char *timestamp)
Send opening tag for BLOB command to server.
Class to provide basic INDI device functionality.
Definition: basedevice.h:52
INDI::PropertyNumber getNumber(const char *name) const
Definition: basedevice.cpp:89
void checkMessage(XMLEle *root)
Definition: basedevice.cpp:842
const char * getDeviceName() const
Definition: basedevice.cpp:821
Property getProperty(const char *name, INDI_PROPERTY_TYPE type=INDI_UNKNOWN) const
Return a property and its type given its name.
Definition: basedevice.cpp:138
INDI::PropertySwitch getSwitch(const char *name) const
Definition: basedevice.cpp:99
int removeProperty(const char *name, char *errmsg)
Remove a property.
Definition: basedevice.cpp:170
bool isValid() const
Definition: basedevice.cpp:904
std::shared_ptr< BaseDevicePrivate > d_ptr
Definition: basedevice.h:308
INDI::PropertyText getText(const char *name) const
Definition: basedevice.cpp:94
XMLEle * handle() const
Definition: indililxml.h:367
std::string tagName() const
Definition: indililxml.h:372
LilXmlAttribute getAttribute(const char *name) const
Definition: indililxml.h:405
std::string toString() const
Definition: indililxml.h:265
The class is used to create device instances. Class copying is not allowed. When an object is destroy...
Definition: parentdevice.h:18
WidgetView< T > * findWidgetByName(const char *name) const
Provides generic container for INDI properties.
Definition: indiproperty.h:48
INDI::PropertyViewSwitch * getSwitch() const
INDI::PropertyViewBlob * getBLOB() const
INDI::PropertyViewText * getText() const
INDI::PropertyViewNumber * getNumber() const
INDI_PROPERTY_TYPE getType() const
void setState(IPState state)
BaseDevice getDeviceByName(const char *name)
int processXml(const INDI::LilXmlElement &root, char *errmsg, const std::function< ParentDevice()> &constructor=[] { return ParentDevice(ParentDevice::Valid);})
bool deleteDevice(const BaseDevice &device)
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IPS_BUSY
Definition: indiapi.h:163
@ INDI_PROPERTY_DUPLICATED
Definition: indibasetypes.h:65
@ INDI_DEVICE_NOT_FOUND
Definition: indibasetypes.h:63
void IDLog(const char *fmt,...)
Definition: indicom.c:316
BLOBHandling
How drivers handle BLOBs incoming from snooping drivers.
Definition: indidevapi.h:266
@ B_ONLY
Definition: indidevapi.h:269
@ B_ALSO
Definition: indidevapi.h:268
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
@ INDI_LIGHT
Definition: indidriver.c:60
@ INDI_TEXT
Definition: indidriver.c:59
@ INDI_UNKNOWN
Definition: indidriver.c:62
@ INDI_NUMBER
Definition: indidriver.c:57
@ INDI_SWITCH
Definition: indidriver.c:58
@ INDI_BLOB
Definition: indidriver.c:61
#define MAXRBUF
Definition: indiserver.cpp:102
void IUUserIOBLOBContextOne(const userio *io, void *user, const char *name, unsigned int size, unsigned int bloblen, const void *blob, const char *format)
Definition: indiuserio.c:101
void IUUserIONewBLOBFinish(const userio *io, void *user)
Definition: indiuserio.c:281
void IUUserIONewBLOB(const userio *io, void *user, const IBLOBVectorProperty *bvp)
Definition: indiuserio.c:251
void IUUserIONewBLOBStart(const userio *io, void *user, const char *dev, const char *name, const char *timestamp)
Definition: indiuserio.c:260
void IUUserIONewText(const userio *io, void *user, const ITextVectorProperty *tvp)
Definition: indiuserio.c:216
void IUUserIOEnableBLOB(const userio *io, void *user, const char *dev, const char *name, BLOBHandling blobH)
Definition: indiuserio.c:341
void IUUserIOPingRequest(const userio *io, void *user, const char *pingUid)
Definition: indiuserio.c:787
void IUUserIONewSwitch(const userio *io, void *user, const ISwitchVectorProperty *svp)
Definition: indiuserio.c:240
void IUUserIONewNumber(const userio *io, void *user, const INumberVectorProperty *nvp)
Definition: indiuserio.c:199
void IUUserIOGetProperties(const userio *io, void *user, const char *dev, const char *name)
Definition: indiuserio.c:307
void IUUserIOPingReply(const userio *io, void *user, const char *pingUid)
Definition: indiuserio.c:794
const char * CONNECTION
Connect to and disconnect from device.
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: json.h:4973
One Blob (Binary Large Object) descriptor.
BLOBHandling blobMode
static PropertyView< T > * cast(PropertyType *raw)
const char * getName() const
const char * getFormat() const
void setState(const ISState &state)
void setText(const char *text, size_t size)
Definition: userio.h:29
int(* vprintf)(void *user, const char *format, va_list arg)
Definition: userio.h:31
ssize_t(* write)(void *user, const void *ptr, size_t count)
Definition: userio.h:30
const struct userio * userio_file()
Definition: userio.c:39