34 #ifdef ENABLE_INDI_SHARED_MEMORY
49 #define snprintf _snprintf
52 #pragma warning(disable : 4996)
60 static char indidev[] =
"INDIDEV=";
62 if (getenv(
"INDIDEV") !=
nullptr)
117 if (oneProp.isNameMatch(name))
118 return oneProp.getState();
126 if (oneProp.isNameMatch(name))
127 return oneProp.getPermission();
141 std::lock_guard<std::mutex> lock(d->m_Lock);
148 if (!oneProp.getRegistered())
151 if (oneProp.isNameMatch(name))
175 std::lock_guard<std::mutex> lock(d->m_Lock);
188 std::this_thread::sleep_for(std::chrono::milliseconds(100));
213 std::string BaseDevice::getSharedFilePath(std::string fileName)
215 std::string pathName;
220 if (stat(fileName.c_str(), &st) == 0)
227 const size_t lastSlashIdx = fileName.find_last_of(
"\\/");
228 if (std::string::npos != lastSlashIdx)
230 fileName.erase(0, lastSlashIdx + 1);
233 const char * indiprefix = getenv(
"INDIPREFIX");
236 #if defined(OSX_EMBEDED_MODE)
237 pathName = std::string(indiprefix) +
"/Contents/Resources/" + fileName;
238 #elif defined(__APPLE__)
239 pathName = std::string(indiprefix) +
"/Contents/Resources/DriverSupport/" + fileName;
241 pathName = std::string(indiprefix) +
"/share/indi/" + fileName;
246 pathName = std::string(DATA_INSTALL_DIR) +
"/" + fileName;
252 static std::string sGetSheletonFilePath(std::string fileName)
254 std::string pathName;
259 const char *indiskel = getenv(
"INDISKEL");
264 IDLog(
"Using INDISKEL %s\n", pathName.c_str());
269 if (stat(fileName.c_str(), &st) == 0)
272 IDLog(
"Using %s\n", pathName.c_str());
277 const size_t lastSlashIdx = fileName.find_last_of(
"\\/");
278 if (std::string::npos != lastSlashIdx)
280 fileName.erase(0, lastSlashIdx + 1);
283 const char * indiprefix = getenv(
"INDIPREFIX");
286 #if defined(OSX_EMBEDED_MODE)
287 pathName = std::string(indiprefix) +
"/Contents/Resources/" + fileName;
288 #elif defined(__APPLE__)
289 pathName = std::string(indiprefix) +
"/Contents/Resources/DriverSupport/" + fileName;
291 pathName = std::string(indiprefix) +
"/share/indi/" + fileName;
296 pathName = std::string(DATA_INSTALL_DIR) +
"/" + fileName;
298 IDLog(
"Using prefix %s\n", pathName.c_str());
302 bool BaseDevice::buildSkeleton(
const char *filename)
306 LilXmlDocument document = d->xmlParser.readFromFile(sGetSheletonFilePath(filename));
310 IDLog(
"Unable to parse skeleton XML: %s", d->xmlParser.errorMessage());
318 buildProp(element, errmsg,
true);
336 static const std::map<INDI_PROPERTY_TYPE, std::string> tagTypeName =
345 const auto rootTagName = root.
tagName();
346 const auto rootTagType = std::find_if(tagTypeName.begin(), tagTypeName.end(), [&rootTagName](
const auto & it)
348 return rootTagName == it.second;
351 if (rootTagType == tagTypeName.end())
353 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> Unable to process tag", rootTagName.c_str());
360 if (getProperty(propertyName).isValid())
365 if (d->deviceName.empty())
369 switch (rootTagType->first)
378 widget.
setParent(typedProperty.getNumber());
380 widget.
setName (element.getAttribute(
"name"));
381 widget.
setLabel (element.getAttribute(
"label"));
383 widget.
setFormat (element.getAttribute(
"format"));
384 widget.
setMin (element.getAttribute(
"min"));
385 widget.
setMax (element.getAttribute(
"max"));
386 widget.
setStep (element.getAttribute(
"step"));
388 widget.
setValue (element.context().toDoubleSexa());
391 typedProperty.push(std::move(widget));
393 property = typedProperty;
404 widget.
setParent(typedProperty.getSwitch());
406 widget.
setName (element.getAttribute(
"name"));
407 widget.
setLabel (element.getAttribute(
"label"));
409 widget.
setState (element.context());
412 typedProperty.push(std::move(widget));
414 property = typedProperty;
425 widget.
setParent(typedProperty.getText());
427 widget.
setName (element.getAttribute(
"name"));
428 widget.
setLabel (element.getAttribute(
"label"));
430 widget.
setText (element.context());
433 typedProperty.push(std::move(widget));
435 property = typedProperty;
446 widget.
setParent(typedProperty.getLight());
448 widget.
setName (element.getAttribute(
"name"));
449 widget.
setLabel (element.getAttribute(
"label"));
451 widget.
setState (element.context());
454 typedProperty.push(std::move(widget));
456 property = typedProperty;
467 widget.
setParent(typedProperty.getBLOB());
469 widget.
setName (element.getAttribute(
"name"));
470 widget.
setLabel (element.getAttribute(
"label"));
472 widget.
setFormat (element.getAttribute(
"format"));
475 typedProperty.push(std::move(widget));
477 property = typedProperty;
487 IDLog(
"%s: invalid name '%s'\n", propertyName, rootTagName.c_str());
493 IDLog(
"%s: %s with no valid members\n", propertyName, rootTagName.c_str());
497 property.setBaseDevice (*
this);
498 property.setName (propertyName);
499 property.setDynamic (isDynamic);
512 d->addProperty(property);
515 d->mediateNewProperty(property);
520 bool BaseDevice::isConnected()
const
526 auto sp = svp.findWidgetByName(
"CONNECT");
528 return sp && sp->getState() ==
ISS_ON && svp.getState() ==
IPS_OK;
531 void BaseDevice::attach()
534 d->mediateNewDevice(*
this);
537 void BaseDevice::detach()
540 d->mediateRemoveDevice(*
this);
544 template <
typename TypedProperty>
545 static void for_property(
552 TypedProperty typedProperty = property;
556 auto * item = typedProperty.findWidgetByName(element.getAttribute(
"name"));
558 function(element, item);
573 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> unable to find name attribute", root.
tagName().c_str());
578 checkMessage(root.
handle());
581 static const std::map<INDI_PROPERTY_TYPE, std::string> tagTypeName =
590 const auto rootTagName = root.
tagName();
591 const auto rootTagType = std::find_if(tagTypeName.begin(), tagTypeName.end(), [&rootTagName](
const auto & it)
593 return rootTagName == it.second;
596 if (rootTagType == tagTypeName.end())
598 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> Unable to process tag", rootTagName.c_str());
605 INDI::Property property = getProperty(propertyName, rootTagType->first);
609 snprintf(errmsg,
MAXRBUF,
"INDI: Could not find property %s in %s", propertyName,
getDeviceName());
633 property.setTimeout(timeoutValue);
637 switch (rootTagType->first)
642 for_property<INDI::PropertyNumber>(root, property, [](
const LilXmlElement & element,
auto * item)
644 item->setValue(element.
context());
656 for_property<INDI::PropertySwitch>(root, property, [](
const LilXmlElement & element,
auto * item)
665 for_property<INDI::PropertyText>(root, property, [](
const LilXmlElement & element,
auto * item)
667 item->setText(element.
context());
674 for_property<INDI::PropertyLight>(root, property, [](
const LilXmlElement & element,
auto * item)
683 if (d->setBLOB(
PropertyBlob(property), root, errmsg) < 0)
692 d->mediateUpdateProperty(property);
697 #ifdef ENABLE_INDI_SHARED_MEMORY
700 auto attachementId = element.
getAttribute(
"attached-data-id");
702 if (!attachementId.isValid())
713 if (
auto directAttachment = element.
getAttribute(
"attachment-direct"))
727 memcpy(widget.
getBlob(), tmp, size);
747 auto widget =
property.findWidgetByName(name);
749 if (!name || !format || !size)
751 snprintf(errmsg,
MAXRBUF,
"INDI: %s.%s.%s No valid members.",
757 if (size.toInt() == 0)
763 #ifdef ENABLE_INDI_SHARED_MEMORY
764 if (sSharedToBlob(element, *widget) ==
false)
767 size_t base64_encoded_size = element.
context().
size();
768 size_t base64_decoded_size = 3 * base64_encoded_size / 4;
774 if (format.endsWith(
".z"))
776 widget->
setFormat(format.toString().substr(0, format.lastIndexOf(
".z")));
778 uLongf dataSize = widget->
getSize() *
sizeof(uint8_t);
779 Bytef *dataBuffer =
static_cast<Bytef *
>(malloc(dataSize));
781 if (dataBuffer ==
nullptr)
783 strncpy(errmsg,
"Unable to allocate memory for data buffer",
MAXRBUF);
786 int r = uncompress(dataBuffer, &dataSize,
static_cast<unsigned char *
>(widget->
getBlob()),
790 snprintf(errmsg,
MAXRBUF,
"INDI: %s.%s.%s compression error: %d",
796 #ifdef ENABLE_INDI_SHARED_MEMORY
809 property.emitUpdate();
815 void BaseDevice::setDeviceName(
const char *dev)
824 return d->deviceName.data();
827 bool BaseDevice::isDeviceNameMatch(
const char *otherName)
const
830 return d->deviceName == otherName;
833 bool BaseDevice::isDeviceNameMatch(
const std::string &otherName)
const
836 return d->deviceName == otherName;
842 void BaseDevice::checkMessage(
XMLEle *root)
872 std::string finalMsg = msgBuffer;
875 addMessage(finalMsg);
878 void BaseDevice::addMessage(
const std::string &msg)
881 std::unique_lock<std::mutex> guard(d->m_Lock);
882 d->messageLog.push_back(msg);
885 d->mediateNewMessage(*
this,
int(d->messageLog.size() - 1));
888 const std::string &BaseDevice::messageQueue(
size_t index)
const
891 std::lock_guard<std::mutex> lock(d->m_Lock);
892 assert(index < d->messageLog.size());
893 return d->messageLog.at(index);
896 const std::string &BaseDevice::lastMessage()
const
899 std::lock_guard<std::mutex> lock(d->m_Lock);
900 assert(d->messageLog.size() != 0);
901 return d->messageLog.back();
904 bool BaseDevice::isValid()
const
910 void BaseDevice::watchProperty(
const char *name,
const std::function<
void(
INDI::Property)> &callback,
WATCH watch)
913 d->watchPropertyMap[name].callback = callback;
914 d->watchPropertyMap[name].watch = watch;
931 auto pContainer = getProperty(property.
getName(), property.
getType());
933 if (pContainer.isValid())
934 pContainer.setRegistered(
true);
936 d->addProperty(property);
942 registerProperty(property);
945 const char *BaseDevice::getDriverName()
const
947 auto driverName = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_NAME");
949 return driverName ? driverName->getText() :
nullptr;
952 const char *BaseDevice::getDriverExec()
const
954 auto driverExec = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_EXEC");
955 return driverExec ? driverExec->getText() :
nullptr;
958 const char *BaseDevice::getDriverVersion()
const
960 auto driverVersion = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_VERSION");
961 return driverVersion ? driverVersion->getText() :
nullptr;
964 uint16_t BaseDevice::getDriverInterface()
const
966 auto driverInterface = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_INTERFACE");
967 return driverInterface ? atoi(driverInterface->getText()) : 0;
973 d->mediator = mediator;
991 return isValid() ? &d->self :
nullptr;
996 #if defined(_MSC_VER)
int from64tobits_fast(char *out, const char *in, int inlen)
BaseDevice::Properties pAll
virtual ~BaseDevicePrivate()
Class to provide basic INDI device functionality.
INDI::PropertyNumber getNumber(const char *name) const
void * getRawProperty(const char *name, INDI_PROPERTY_TYPE type=INDI_UNKNOWN) const
Return a property and its type given its name.
Property getProperty(const char *name, INDI_PROPERTY_TYPE type=INDI_UNKNOWN) const
Return a property and its type given its name.
INDI::PropertySwitch getSwitch(const char *name) const
int removeProperty(const char *name, char *errmsg)
Remove a property.
INDI::PropertyBlob getBLOB(const char *name) const
INDI::PropertyLight getLight(const char *name) const
INDI::PropertyText getText(const char *name) const
IPerm getPropertyPermission(const char *name) const
IPState getPropertyState(const char *name) const
Properties getProperties()
Return a list of all properties in the device.
LilXmlElement root() const
Elements getElementsByTagName(const char *tagName) const
Elements getElements() const
LilXmlValue context() const
std::string tagName() const
LilXmlAttribute getAttribute(const char *name) const
IPState toIPState(safe_ptr< bool > ok=nullptr) const
std::string toString() const
double toDouble(safe_ptr< bool > ok=nullptr) const
IPerm toIPerm(safe_ptr< bool > ok=nullptr) const
const char * toCString() const
const char * getName() const
void setRule(ISRule rule)
Provides generic container for INDI properties.
const char * getDeviceName() const
const char * getName() const
void * getProperty() const
bool isNameMatch(const char *otherName) const
INDI_PROPERTY_TYPE getType() const
void setState(IPState state)
IPerm
Permission hint, with respect to client.
@ INDI_PROPERTY_DUPLICATED
void IDLog(const char *fmt,...)
const char * indi_timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Implementations for common driver routines.
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
const char * CONNECTION
Connect to and disconnect from device.
Namespace to encapsulate INDI client, drivers, and mediator classes.
void * attachBlobByUid(const std::string &identifier, size_t size)
const char * getDeviceName()
void IDSharedBlobFree(void *ptr)
void setName(const char *name)
void setText(const char *text, size_t size)
void setParent(ITextVectorProperty *parent)
void setLabel(const char *label)
bool isNameMatch(const char *otherName) const