35#ifdef ENABLE_INDI_SHARED_MEMORY
50#define snprintf _snprintf
53#pragma warning(disable : 4996)
61 static char indidev[] =
"INDIDEV=";
63 if (getenv(
"INDIDEV") !=
nullptr)
118 if (oneProp.isNameMatch(name))
119 return oneProp.getState();
127 if (oneProp.isNameMatch(name))
128 return oneProp.getPermission();
142 std::lock_guard<std::mutex> lock(d->m_Lock);
149 if (!oneProp.getRegistered())
152 if (oneProp.isNameMatch(name))
176 std::lock_guard<std::mutex> lock(d->m_Lock);
189 std::this_thread::sleep_for(std::chrono::milliseconds(100));
214std::string BaseDevice::getSharedFilePath(std::string fileName)
216 std::string pathName;
221 if (stat(fileName.c_str(), &st) == 0)
228 const size_t lastSlashIdx = fileName.find_last_of(
"\\/");
229 if (std::string::npos != lastSlashIdx)
231 fileName.erase(0, lastSlashIdx + 1);
234 const char * indiprefix = getenv(
"INDIPREFIX");
237#if defined(OSX_EMBEDED_MODE)
238 pathName = std::string(indiprefix) +
"/Contents/Resources/" + fileName;
239#elif defined(__APPLE__)
240 pathName = std::string(indiprefix) +
"/Contents/Resources/DriverSupport/" + fileName;
242 pathName = std::string(indiprefix) +
"/share/indi/" + fileName;
247 pathName = std::string(DATA_INSTALL_DIR) +
"/" + fileName;
253static std::string sGetSheletonFilePath(std::string fileName)
255 std::string pathName;
260 const char *indiskel = getenv(
"INDISKEL");
265 IDLog(
"Using INDISKEL %s\n", pathName.c_str());
270 if (stat(fileName.c_str(), &st) == 0)
273 IDLog(
"Using %s\n", pathName.c_str());
278 const size_t lastSlashIdx = fileName.find_last_of(
"\\/");
279 if (std::string::npos != lastSlashIdx)
281 fileName.erase(0, lastSlashIdx + 1);
284 const char * indiprefix = getenv(
"INDIPREFIX");
287#if defined(OSX_EMBEDED_MODE)
288 pathName = std::string(indiprefix) +
"/Contents/Resources/" + fileName;
289#elif defined(__APPLE__)
290 pathName = std::string(indiprefix) +
"/Contents/Resources/DriverSupport/" + fileName;
292 pathName = std::string(indiprefix) +
"/share/indi/" + fileName;
297 pathName = std::string(DATA_INSTALL_DIR) +
"/" + fileName;
299 IDLog(
"Using prefix %s\n", pathName.c_str());
303bool BaseDevice::buildSkeleton(
const char *filename)
307 LilXmlDocument document = d->xmlParser.readFromFile(sGetSheletonFilePath(filename));
311 IDLog(
"Unable to parse skeleton XML: %s", d->xmlParser.errorMessage());
319 buildProp(element, errmsg,
true);
337 static const std::map<INDI_PROPERTY_TYPE, std::string> tagTypeName =
346 const auto rootTagName = root.
tagName();
347 const auto rootTagType = std::find_if(tagTypeName.begin(), tagTypeName.end(), [&rootTagName](
const auto & it)
349 return rootTagName == it.second;
352 if (rootTagType == tagTypeName.end())
354 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> Unable to process tag", rootTagName.c_str());
361 if (getProperty(propertyName).isValid())
366 if (d->deviceName.empty())
370 switch (rootTagType->first)
379 widget.
setParent(typedProperty.getNumber());
381 widget.
setName (element.getAttribute(
"name"));
382 widget.
setLabel (element.getAttribute(
"label"));
384 widget.
setFormat (element.getAttribute(
"format"));
385 widget.
setMin (element.getAttribute(
"min"));
386 widget.
setMax (element.getAttribute(
"max"));
387 widget.
setStep (element.getAttribute(
"step"));
389 widget.
setValue (element.context().toDoubleSexa());
392 typedProperty.push(std::move(widget));
394 property = typedProperty;
405 widget.
setParent(typedProperty.getSwitch());
407 widget.
setName (element.getAttribute(
"name"));
408 widget.
setLabel (element.getAttribute(
"label"));
410 widget.
setState (element.context());
413 typedProperty.push(std::move(widget));
415 property = typedProperty;
426 widget.
setParent(typedProperty.getText());
428 widget.
setName (element.getAttribute(
"name"));
429 widget.
setLabel (element.getAttribute(
"label"));
431 widget.
setText (element.context());
434 typedProperty.push(std::move(widget));
436 property = typedProperty;
447 widget.
setParent(typedProperty.getLight());
449 widget.
setName (element.getAttribute(
"name"));
450 widget.
setLabel (element.getAttribute(
"label"));
452 widget.
setState (element.context());
455 typedProperty.push(std::move(widget));
457 property = typedProperty;
466#ifdef ENABLE_INDI_SHARED_MEMORY
477 widget.
setParent(typedProperty.getBLOB());
479 widget.
setName (element.getAttribute(
"name"));
480 widget.
setLabel (element.getAttribute(
"label"));
482 widget.
setFormat (element.getAttribute(
"format"));
485 typedProperty.push(std::move(widget));
487 property = typedProperty;
497 IDLog(
"%s: invalid name '%s'\n", propertyName, rootTagName.c_str());
503 IDLog(
"%s: %s with no valid members\n", propertyName, rootTagName.c_str());
507 property.setBaseDevice (*
this);
508 property.setName (propertyName);
509 property.setDynamic (isDynamic);
522 d->addProperty(property);
525 d->mediateNewProperty(property);
530bool BaseDevice::isConnected()
const
536 auto sp = svp.findWidgetByName(
"CONNECT");
538 return sp && sp->getState() ==
ISS_ON && svp.getState() ==
IPS_OK;
541void BaseDevice::attach()
544 d->mediateNewDevice(*
this);
547void BaseDevice::detach()
550 d->mediateRemoveDevice(*
this);
554template <
typename TypedProperty>
555static void for_property(
562 TypedProperty typedProperty = property;
564 for (
const auto &element : root.getElements())
566 auto * item = typedProperty.findWidgetByName(element.getAttribute(
"name"));
568 function(element, item);
571 typedProperty.emitUpdate();
583 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> unable to find name attribute", root.
tagName().c_str());
588 checkMessage(root.
handle());
591 static const std::map<INDI_PROPERTY_TYPE, std::string> tagTypeName =
600 const auto rootTagName = root.
tagName();
601 const auto rootTagType = std::find_if(tagTypeName.begin(), tagTypeName.end(), [&rootTagName](
const auto & it)
603 return rootTagName == it.second;
606 if (rootTagType == tagTypeName.end())
608 snprintf(errmsg,
MAXRBUF,
"INDI: <%s> Unable to process tag", rootTagName.c_str());
615 INDI::Property property = getProperty(propertyName, rootTagType->first);
619 snprintf(errmsg,
MAXRBUF,
"INDI: Could not find property %s in %s", propertyName,
getDeviceName());
643 property.setTimeout(timeoutValue);
647 switch (rootTagType->first)
652 for_property<INDI::PropertyNumber>(root, property, [](
const LilXmlElement & element,
auto * item)
654 item->setValue(element.
context());
666 for_property<INDI::PropertySwitch>(root, property, [](
const LilXmlElement & element,
auto * item)
675 for_property<INDI::PropertyText>(root, property, [](
const LilXmlElement & element,
auto * item)
677 item->setText(element.
context());
684 for_property<INDI::PropertyLight>(root, property, [](
const LilXmlElement & element,
auto * item)
693 if (d->setBLOB(
PropertyBlob(property), root, errmsg) < 0)
702 d->mediateUpdateProperty(property);
707#ifdef ENABLE_INDI_SHARED_MEMORY
710 auto attachementId = element.
getAttribute(
"attached-data-id");
712 if (!attachementId.isValid())
723 if (
auto directAttachment = element.
getAttribute(
"attachment-direct"))
737 memcpy(widget.
getBlob(), tmp, size);
757 auto widget =
property.findWidgetByName(name);
759 if (!name || !format || !size)
761 snprintf(errmsg,
MAXRBUF,
"INDI: %s.%s.%s No valid members.",
767 if (size.toInt() == 0)
773#ifdef ENABLE_INDI_SHARED_MEMORY
774 if (sSharedToBlob(element, *widget) ==
false)
777 size_t base64_encoded_size = element.
context().
size();
778 size_t base64_decoded_size = 3 * base64_encoded_size / 4;
784 if (format.endsWith(
".z"))
786 widget->
setFormat(format.toString().substr(0, format.lastIndexOf(
".z")));
788 uLongf dataSize = widget->
getSize() *
sizeof(uint8_t);
789 Bytef *dataBuffer =
static_cast<Bytef *
>(malloc(dataSize));
791 if (dataBuffer ==
nullptr)
793 strncpy(errmsg,
"Unable to allocate memory for data buffer",
MAXRBUF);
796 int r = uncompress(dataBuffer, &dataSize,
static_cast<unsigned char *
>(widget->
getBlob()),
800 snprintf(errmsg,
MAXRBUF,
"INDI: %s.%s.%s compression error: %d",
806#ifdef ENABLE_INDI_SHARED_MEMORY
819 property.emitUpdate();
825void BaseDevice::setDeviceName(
const char *dev)
831const char *BaseDevice::getDeviceName()
const
834 return d->deviceName.data();
837bool BaseDevice::isDeviceNameMatch(
const char *otherName)
const
840 return d->deviceName == otherName;
843bool BaseDevice::isDeviceNameMatch(
const std::string &otherName)
const
846 return d->deviceName == otherName;
852void BaseDevice::checkMessage(
XMLEle *root)
882 std::string finalMsg = msgBuffer;
885 addMessage(finalMsg);
888void BaseDevice::addMessage(
const std::string &msg)
891 std::unique_lock<std::mutex> guard(d->m_Lock);
892 d->messageLog.push_back(msg);
895 d->mediateNewMessage(*
this,
int(d->messageLog.size() - 1));
898const std::string &BaseDevice::messageQueue(
size_t index)
const
901 std::lock_guard<std::mutex> lock(d->m_Lock);
906 return d->messageLog.at(index);
909const std::string &BaseDevice::lastMessage()
const
912 std::lock_guard<std::mutex> lock(d->m_Lock);
913 assert(d->messageLog.size() != 0);
914 return d->messageLog.back();
917bool BaseDevice::isValid()
const
925 return d_ptr == other.
d_ptr;
928void BaseDevice::watchProperty(
const char *name,
const std::function<
void(
INDI::Property)> &callback,
WATCH watch)
931 d->watchPropertyMap[name].callback = callback;
932 d->watchPropertyMap[name].watch = watch;
949 auto pContainer = getProperty(property.
getName(), property.
getType());
951 if (pContainer.isValid())
952 pContainer.setRegistered(
true);
954 d->addProperty(property);
960 registerProperty(property);
963const char *BaseDevice::getDriverName()
const
965 auto driverName = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_NAME");
967 return driverName ? driverName->getText() :
nullptr;
970const char *BaseDevice::getDriverExec()
const
972 auto driverExec = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_EXEC");
973 return driverExec ? driverExec->getText() :
nullptr;
976const char *BaseDevice::getDriverVersion()
const
978 auto driverVersion = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_VERSION");
979 return driverVersion ? driverVersion->getText() :
nullptr;
982uint16_t BaseDevice::getDriverInterface()
const
984 auto driverInterface = getText(
"DRIVER_INFO").findWidgetByName(
"DRIVER_INTERFACE");
985 return driverInterface ? atoi(driverInterface->getText()) : 0;
991 d->mediator = mediator;
1009 return isValid() ? &d->self :
nullptr;
1014#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
std::shared_ptr< BaseDevicePrivate > d_ptr
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 * getDeviceName() const
const char * getName() const
void setBlobDeleter(const std::function< void(void *&)> &deleter)
Set the Blob Deleter function You can define a function to release the memory of the elements....
void setRule(ISRule rule)
Provides generic container for INDI properties.
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)
void IDSharedBlobFree(void *ptr)
Free a buffer allocated using IDSharedBlobAlloc. Fall back to free for buffer that are not shared blo...
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