Instrument Neutral Distributed Interface INDI  1.9.2
basedevice.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2011 Jasem Mutlaq. All rights reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "basedevice.h"
20 #include "basedevice_p.h"
21 
22 #include "base64.h"
23 #include "config.h"
24 #include "indicom.h"
25 #include "indistandardproperty.h"
26 #include "locale_compat.h"
27 
28 #include "indipropertytext.h"
29 #include "indipropertynumber.h"
30 #include "indipropertyswitch.h"
31 #include "indipropertylight.h"
32 #include "indipropertyblob.h"
33 
34 #include <cerrno>
35 #include <cassert>
36 #include <cstdlib>
37 #include <cstring>
38 #include <zlib.h>
39 #include <sys/stat.h>
40 #include <thread>
41 #include <chrono>
42 #include <algorithm>
43 
44 #if defined(_MSC_VER)
45 #define snprintf _snprintf
46 #pragma warning(push)
47 #pragma warning(disable : 4996)
49 #endif
50 
51 namespace INDI
52 {
53 
55 {
56  static char indidev[] = "INDIDEV=";
57  lp = newLilXML();
58 
59  if (getenv("INDIDEV") != nullptr)
60  {
61  deviceName = getenv("INDIDEV");
62  putenv(indidev);
63  }
64 }
65 
67 {
68  delLilXML(lp);
69  pAll.clear();
70 }
71 
73  : d_ptr(new BaseDevicePrivate)
74 { }
75 
77 { }
78 
79 BaseDevice::BaseDevice(BaseDevicePrivate &dd)
80  : d_ptr(&dd)
81 { }
82 
84 {
85  return static_cast<PropertyView<INumber> *>(getRawProperty(name, INDI_NUMBER));
86 }
87 
89 {
90  return static_cast<PropertyView<IText> *>(getRawProperty(name, INDI_TEXT));
91 }
92 
94 {
95  return static_cast<PropertyView<ISwitch> *>(getRawProperty(name, INDI_SWITCH));
96 }
97 
98 INDI::PropertyView<ILight> *BaseDevice::getLight(const char *name) const
99 {
100  return static_cast<PropertyView<ILight> *>(getRawProperty(name, INDI_LIGHT));
101 }
102 
103 INDI::PropertyView<IBLOB> *BaseDevice::getBLOB(const char *name) const
104 {
105  return static_cast<PropertyView<IBLOB> *>(getRawProperty(name, INDI_BLOB));
106 }
107 
108 IPState BaseDevice::getPropertyState(const char *name) const
109 {
110  for (const auto &oneProp : getProperties())
111  if (oneProp.isNameMatch(name))
112  return oneProp.getState();
113 
114  return IPS_IDLE;
115 }
116 
117 IPerm BaseDevice::getPropertyPermission(const char *name) const
118 {
119  for (const auto &oneProp : getProperties())
120  if (oneProp.isNameMatch(name))
121  return oneProp.getPermission();
122 
123  return IP_RO;
124 }
125 
126 void *BaseDevice::getRawProperty(const char *name, INDI_PROPERTY_TYPE type) const
127 {
128  INDI::Property *prop = getProperty(name, type);
129  return prop != nullptr ? prop->getProperty() : nullptr;
130 }
131 
133 {
134  D_PTR(const BaseDevice);
135  std::lock_guard<std::mutex> lock(d->m_Lock);
136 
137  for (const auto &oneProp : getProperties())
138  {
139  if (type != oneProp.getType() && type != INDI_UNKNOWN)
140  continue;
141 
142  if (!oneProp.getRegistered())
143  continue;
144 
145  if (oneProp.isNameMatch(name))
146  return oneProp;
147  }
148 
149  return INDI::Property();
150 }
151 
153 {
154  D_PTR(BaseDevice);
155  return d->pAll;
156 }
157 
159 {
160  D_PTR(const BaseDevice);
161  return d->pAll;
162 }
163 
164 int BaseDevice::removeProperty(const char *name, char *errmsg)
165 {
166  D_PTR(BaseDevice);
167  int result = INDI_PROPERTY_INVALID;
168 
169  std::lock_guard<std::mutex> lock(d->m_Lock);
170 
171  d->pAll.erase_if([&name, &result](INDI::Property & prop) -> bool
172  {
173 #if 0
174  if (prop.isNameMatch(name))
175  {
176  // JM 2021-04-28: delete later. We perform the actual delete after 100ms to give clients a chance to remove the object.
177  // This is necessary when rapid define-delete-define sequences are made.
178  // This HACK is not ideal. We need to start using std::shared_ptr for this purpose soon, but this will be a major change to the
179  // interface. Perhaps for INDI 2.0
180  std::thread([prop]
181  {
182  std::this_thread::sleep_for(std::chrono::milliseconds(100));
183  }).detach();
184  result = 0;
185  return true;
186  }
187  else
188  {
189  return false;
190  }
191 #endif
192  if (prop.isNameMatch(name))
193  {
194  result = 0;
195  return true;
196  }
197  else
198  return false;
199  });
200 
201  if (result != 0)
202  snprintf(errmsg, MAXRBUF, "Error: Property %s not found in device %s.", name, getDeviceName());
203 
204  return result;
205 }
206 
207 bool BaseDevice::buildSkeleton(const char *filename)
208 {
209  D_PTR(BaseDevice);
210  char errmsg[MAXRBUF];
211  FILE *fp = nullptr;
212  XMLEle *root = nullptr, *fproot = nullptr;
213 
214  char pathname[MAXRBUF];
215  struct stat st;
216  const char *indiskel = getenv("INDISKEL");
217  if (indiskel)
218  {
219  strncpy(pathname, indiskel, MAXRBUF - 1);
220  pathname[MAXRBUF - 1] = 0;
221  IDLog("Using INDISKEL %s\n", pathname);
222  }
223  else
224  {
225  if (stat(filename, &st) == 0)
226  {
227  strncpy(pathname, filename, MAXRBUF - 1);
228  pathname[MAXRBUF - 1] = 0;
229  IDLog("Using %s\n", pathname);
230  }
231  else
232  {
233  const char *slash = strrchr(filename, '/');
234  if (slash)
235  filename = slash + 1;
236  const char *indiprefix = getenv("INDIPREFIX");
237  if (indiprefix)
238  {
239 #if defined(OSX_EMBEDED_MODE)
240  snprintf(pathname, MAXRBUF - 1, "%s/Contents/Resources/%s", indiprefix, filename);
241 #elif defined(__APPLE__)
242  snprintf(pathname, MAXRBUF - 1, "%s/Contents/Resources/DriverSupport/%s", indiprefix, filename);
243 #else
244  snprintf(pathname, MAXRBUF - 1, "%s/share/indi/%s", indiprefix, filename);
245 #endif
246  }
247  else
248  {
249  snprintf(pathname, MAXRBUF - 1, "%s/%s", DATA_INSTALL_DIR, filename);
250  }
251  pathname[MAXRBUF - 1] = 0;
252  IDLog("Using prefix %s\n", pathname);
253  }
254  }
255 
256  fp = fopen(pathname, "r");
257 
258  if (fp == nullptr)
259  {
260  IDLog("Unable to build skeleton. Error loading file %s: %s\n", pathname, strerror(errno));
261  return false;
262  }
263 
264  fproot = readXMLFile(fp, d->lp, errmsg);
265  fclose(fp);
266 
267  if (fproot == nullptr)
268  {
269  IDLog("Unable to parse skeleton XML: %s", errmsg);
270  return false;
271  }
272 
273  //prXMLEle(stderr, fproot, 0);
274 
275  for (root = nextXMLEle(fproot, 1); root != nullptr; root = nextXMLEle(fproot, 0))
276  buildProp(root, errmsg);
277 
278  delXMLEle(fproot);
279  return true;
280  /**************************************************************************/
281 }
282 
283 int BaseDevice::buildProp(XMLEle *root, char *errmsg)
284 {
285  D_PTR(BaseDevice);
286  IPerm perm = IP_RO;
287  IPState state = IPS_IDLE;
288  XMLEle *ep = nullptr;
289  char *rtag, *rname, *rdev;
290 
291  INDI::Property indiProp;
292 
293  rtag = tagXMLEle(root);
294 
295  /* pull out device and name */
296  if (crackDN(root, &rdev, &rname, errmsg) < 0)
297  return -1;
298 
299  if (d->deviceName.empty())
300  d->deviceName = rdev;
301 
302  if (getProperty(rname).isValid())
304 
305  if (strcmp(rtag, "defLightVector") && crackIPerm(findXMLAttValu(root, "perm"), &perm) < 0)
306  {
307  IDLog("Error extracting %s permission (%s)\n", rname, findXMLAttValu(root, "perm"));
308  return -1;
309  }
310 
311  if (crackIPState(findXMLAttValu(root, "state"), &state) < 0)
312  {
313  IDLog("Error extracting %s state (%s)\n", rname, findXMLAttValu(root, "state"));
314  return -1;
315  }
316 
317  if (!strcmp(rtag, "defNumberVector"))
318  {
319  AutoCNumeric locale;
320 
321  INDI::PropertyNumber nvp {0};
322 
323  /* pull out each name/value pair */
324  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
325  {
326  if (strcmp(tagXMLEle(ep), "defNumber"))
327  continue;
328 
330  np.setName(findXMLAttValu(ep, "name"));
331  if (np.getName()[0] == '\0')
332  continue;
333 
334  double value;
335  if (f_scansexa(pcdataXMLEle(ep), &value) < 0)
336  {
337  IDLog("%s: Bad format %s\n", rname, pcdataXMLEle(ep));
338  continue;
339  }
340 
341  np.setValue(value);
342  np.setLabel(findXMLAttValu(ep, "label"));
343  np.setFormat(findXMLAttValu(ep, "format"));
344 
345  np.setMin(atof(findXMLAttValu(ep, "min")));
346  np.setMax(atof(findXMLAttValu(ep, "max")));
347  np.setStep(atof(findXMLAttValu(ep, "step")));
348 
349  np.setParent(nvp->getNumber());
350 
351  nvp.push(std::move(np));
352  }
353 
354  indiProp = nvp;
355  }
356  else if (!strcmp(rtag, "defSwitchVector"))
357  {
358 
359  ISRule rule = ISR_1OFMANY;
360  if (crackISRule(findXMLAttValu(root, "rule"), &rule) < 0)
361  rule = ISR_1OFMANY;
362 
363  INDI::PropertySwitch svp {0};
364  svp.setRule(rule);
365 
366  /* pull out each name/value pair */
367  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
368  {
369  if (strcmp(tagXMLEle(ep), "defSwitch"))
370  continue;
371 
373  sp.setName(findXMLAttValu(ep, "name"));
374  if (sp.getName()[0] == '\0')
375  continue;
376 
377  ISState state;
378  crackISState(pcdataXMLEle(ep), &state);
379 
380  sp.setState(state);
381  sp.setLabel(findXMLAttValu(ep, "label"));
382 
383  sp.setParent(svp->getSwitch());
384 
385  svp.push(std::move(sp));
386  }
387 
388  indiProp = svp;
389  }
390 
391  else if (!strcmp(rtag, "defTextVector"))
392  {
393  INDI::PropertyText tvp {0};
394 
395  // pull out each name/value pair
396  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
397  {
398  if (strcmp(tagXMLEle(ep), "defText"))
399  continue;
400 
402  tp.setName(findXMLAttValu(ep, "name"));
403  if (tp.getName()[0] == '\0')
404  continue;
405 
406  tp.setText(pcdataXMLEle(ep), pcdatalenXMLEle(ep));
407  tp.setLabel(findXMLAttValu(ep, "label"));
408 
409  tp.setParent(tvp->getText());
410 
411  tvp.push(std::move(tp));
412  }
413 
414  indiProp = tvp;
415  }
416  else if (!strcmp(rtag, "defLightVector"))
417  {
418  INDI::PropertyLight lvp {0};
419 
420  /* pull out each name/value pair */
421  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
422  {
423  if (strcmp(tagXMLEle(ep), "defLight"))
424  continue;
425 
427  lp.setName(findXMLAttValu(ep, "name"));
428  if (lp.getName()[0] == '\0')
429  continue;
430 
431  IPState state;
432  crackIPState(pcdataXMLEle(ep), &state);
433  lp.setState(state);
434  lp.setLabel(findXMLAttValu(ep, "label"));
435 
436  lp.setParent(lvp.getLight());
437 
438  lvp.push(std::move(lp));
439  }
440 
441  indiProp = lvp;
442  }
443  else if (!strcmp(rtag, "defBLOBVector"))
444  {
445  INDI::PropertyBlob bvp {0};
446 
447  /* pull out each name/value pair */
448  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
449  {
450  if (strcmp(tagXMLEle(ep), "defBLOB"))
451  continue;
452 
454  bp.setName(findXMLAttValu(ep, "name"));
455  if (bp.getName()[0] == '\0')
456  continue;
457 
458  bp.setLabel(findXMLAttValu(ep, "label"));
459  bp.setFormat(findXMLAttValu(ep, "format"));
460 
461  bp.setParent(bvp.getBLOB());
462 
463  bvp.push(std::move(bp));
464  }
465 
466  indiProp = bvp;
467  }
468 
469  if (!indiProp.isValid())
470  {
471  IDLog("%s: invalid name '%s'\n", rname, rtag);
472  return 0;
473  }
474 
475  if (indiProp.isEmpty())
476  {
477  IDLog("%s: %s with no valid members\n", rname, rtag);
478  return 0;
479  }
480 
481  indiProp.setBaseDevice(this);
482  //indiProp.setDynamic(true);
483  indiProp.setDeviceName(getDeviceName());
484  indiProp.setName(rname);
485  indiProp.setLabel(findXMLAttValu(root, "label"));
486  indiProp.setGroupName(findXMLAttValu(root, "group"));
487  indiProp.setPermission(perm);
488  indiProp.setState(state);
489  indiProp.setTimeout(atoi(findXMLAttValu(root, "timeout")));
490 
491  std::unique_lock<std::mutex> lock(d->m_Lock);
492  d->pAll.push_back(indiProp);
493  lock.unlock();
494 
495  //IDLog("Adding number property %s to list.\n", indiProp->getName());
496  if (d->mediator)
497  d->mediator->newProperty(indiProp);
498 
499  return (0);
500 }
501 
502 bool BaseDevice::isConnected() const
503 {
504  auto svp = getSwitch(INDI::SP::CONNECTION);
505  if (!svp)
506  return false;
507 
508  auto sp = svp->findWidgetByName("CONNECT");
509 
510  return sp && sp->getState() == ISS_ON && svp->getState() == IPS_OK;
511 }
512 
513 /*
514  * return 0 if ok else -1 with reason in errmsg
515  */
516 int BaseDevice::setValue(XMLEle *root, char *errmsg)
517 {
518  D_PTR(BaseDevice);
519  XMLEle *ep = nullptr;
520  char *name = nullptr;
521  double timeout = 0;
522  IPState state = IPS_IDLE;
523  bool stateSet = false, timeoutSet = false;
524 
525  char *rtag = tagXMLEle(root);
526 
527  XMLAtt *ap = findXMLAtt(root, "name");
528  if (!ap)
529  {
530  snprintf(errmsg, MAXRBUF, "INDI: <%s> unable to find name attribute", tagXMLEle(root));
531  return (-1);
532  }
533 
534  name = valuXMLAtt(ap);
535 
536  /* set overall property state, if any */
537  ap = findXMLAtt(root, "state");
538  if (ap)
539  {
540  if (crackIPState(valuXMLAtt(ap), &state) != 0)
541  {
542  snprintf(errmsg, MAXRBUF, "INDI: <%s> bogus state %s for %s", tagXMLEle(root), valuXMLAtt(ap), name);
543  return (-1);
544  }
545 
546  stateSet = true;
547  }
548 
549  /* allow changing the timeout */
550  ap = findXMLAtt(root, "timeout");
551  if (ap)
552  {
553  AutoCNumeric locale;
554  timeout = atof(valuXMLAtt(ap));
555  timeoutSet = true;
556  }
557 
558  checkMessage(root);
559 
560  if (!strcmp(rtag, "setNumberVector"))
561  {
562  auto nvp = getNumber(name);
563  if (!nvp)
564  {
565  snprintf(errmsg, MAXRBUF, "INDI: Could not find property %s in %s", name, getDeviceName());
566  return -1;
567  }
568 
569  if (stateSet)
570  nvp->setState(state);
571 
572  if (timeoutSet)
573  nvp->setTimeout(timeout);
574 
575  AutoCNumeric locale;
576 
577  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
578  {
579  auto np = nvp->findWidgetByName(findXMLAttValu(ep, "name"));
580  if (!np)
581  continue;
582 
583  np->setValue(atof(pcdataXMLEle(ep)));
584 
585  // Permit changing of min/max
586  if (findXMLAtt(ep, "min"))
587  np->setMin(atof(findXMLAttValu(ep, "min")));
588  if (findXMLAtt(ep, "max"))
589  np->setMax(atof(findXMLAttValu(ep, "max")));
590  }
591 
592  locale.Restore();
593 
594  if (d->mediator)
595  d->mediator->newNumber(nvp);
596 
597  return 0;
598  }
599  else if (!strcmp(rtag, "setTextVector"))
600  {
601  auto tvp = getText(name);
602  if (!tvp)
603  return -1;
604 
605  if (stateSet)
606  tvp->setState(state);
607 
608  if (timeoutSet)
609  tvp->setTimeout(timeout);
610 
611  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
612  {
613  auto tp = tvp->findWidgetByName(findXMLAttValu(ep, "name"));
614  if (!tp)
615  continue;
616 
617  tp->setText(pcdataXMLEle(ep));
618  }
619 
620  if (d->mediator)
621  d->mediator->newText(tvp);
622 
623  return 0;
624  }
625  else if (!strcmp(rtag, "setSwitchVector"))
626  {
627  ISState swState;
628  auto svp = getSwitch(name);
629  if (!svp)
630  return -1;
631 
632  if (stateSet)
633  svp->setState(state);
634 
635  if (timeoutSet)
636  svp->setTimeout(timeout);
637 
638  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
639  {
640  auto sp = svp->findWidgetByName(findXMLAttValu(ep, "name"));
641  if (!sp)
642  continue;
643 
644  if (crackISState(pcdataXMLEle(ep), &swState) == 0)
645  sp->setState(swState);
646  }
647 
648  if (d->mediator)
649  d->mediator->newSwitch(svp);
650 
651  return 0;
652  }
653  else if (!strcmp(rtag, "setLightVector"))
654  {
655  IPState lState;
656  auto lvp = getLight(name);
657 
658  if (!lvp)
659  return -1;
660 
661  if (stateSet)
662  lvp->setState(state);
663 
664  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
665  {
666  auto lp = lvp->findWidgetByName(findXMLAttValu(ep, "name"));
667  if (!lp)
668  continue;
669 
670  if (crackIPState(pcdataXMLEle(ep), &lState) == 0)
671  lp->setState(lState);
672  }
673 
674  if (d->mediator)
675  d->mediator->newLight(lvp);
676 
677  return 0;
678  }
679  else if (!strcmp(rtag, "setBLOBVector"))
680  {
681  auto bvp = getBLOB(name);
682 
683  if (!bvp)
684  return -1;
685 
686  if (stateSet)
687  bvp->setState(state);
688 
689  if (timeoutSet)
690  bvp->setTimeout(timeout);
691 
692  return setBLOB(bvp, root, errmsg);
693  }
694 
695  snprintf(errmsg, MAXRBUF, "INDI: <%s> Unable to process tag", tagXMLEle(root));
696  return -1;
697 }
698 
699 /* Set BLOB vector. Process incoming data stream
700  * Return 0 if okay, -1 if error
701 */
702 int BaseDevice::setBLOB(IBLOBVectorProperty *bvp, XMLEle *root, char *errmsg)
703 {
704  D_PTR(BaseDevice);
705  /* pull out each name/BLOB pair, decode */
706  for (XMLEle *ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
707  {
708  if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
709  {
710  XMLAtt *na = findXMLAtt(ep, "name");
711 
712  IBLOB *blobEL = IUFindBLOB(bvp, findXMLAttValu(ep, "name"));
713 
714  XMLAtt *fa = findXMLAtt(ep, "format");
715  XMLAtt *sa = findXMLAtt(ep, "size");
716  if (na && fa && sa)
717  {
718  int blobSize = atoi(valuXMLAtt(sa));
719 
720  /* Blob size = 0 when only state changes */
721  if (blobSize == 0)
722  {
723  if (d->mediator)
724  d->mediator->newBLOB(blobEL);
725  continue;
726  }
727 
728  blobEL->size = blobSize;
729  uint32_t base64_encoded_size = pcdatalenXMLEle(ep);
730  uint32_t base64_decoded_size = 3 * base64_encoded_size / 4;
731  blobEL->blob = static_cast<unsigned char *>(realloc(blobEL->blob, base64_decoded_size));
732  blobEL->bloblen = from64tobits_fast(static_cast<char *>(blobEL->blob), pcdataXMLEle(ep), base64_encoded_size);
733 
734  strncpy(blobEL->format, valuXMLAtt(fa), MAXINDIFORMAT);
735 
736  if (strstr(blobEL->format, ".z"))
737  {
738  blobEL->format[strlen(blobEL->format) - 2] = '\0';
739  uLongf dataSize = blobEL->size * sizeof(uint8_t);
740  uint8_t *dataBuffer = static_cast<uint8_t *>(malloc(dataSize));
741 
742  if (dataBuffer == nullptr)
743  {
744  strncpy(errmsg, "Unable to allocate memory for data buffer", MAXRBUF);
745  return (-1);
746  }
747 
748  int r = uncompress(dataBuffer, &dataSize, static_cast<unsigned char *>(blobEL->blob),
749  static_cast<uLong>(blobEL->bloblen));
750  if (r != Z_OK)
751  {
752  snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s compression error: %d", blobEL->bvp->device,
753  blobEL->bvp->name, blobEL->name, r);
754  free(dataBuffer);
755  return -1;
756  }
757  blobEL->size = dataSize;
758  free(blobEL->blob);
759  blobEL->blob = dataBuffer;
760  }
761 
762  if (d->mediator)
763  d->mediator->newBLOB(blobEL);
764  }
765  else
766  {
767  snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s No valid members.", blobEL->bvp->device, blobEL->bvp->name,
768  blobEL->name);
769  return -1;
770  }
771  }
772  }
773 
774  return 0;
775 }
776 
777 void BaseDevice::setDeviceName(const char *dev)
778 {
779  D_PTR(BaseDevice);
780  d->deviceName = dev;
781 }
782 
783 const char *BaseDevice::getDeviceName() const
784 {
785  D_PTR(const BaseDevice);
786  return d->deviceName.data();
787 }
788 
789 bool BaseDevice::isDeviceNameMatch(const char *otherName) const
790 {
791  D_PTR(const BaseDevice);
792  return d->deviceName == otherName;
793 }
794 
795 bool BaseDevice::isDeviceNameMatch(const std::string &otherName) const
796 {
797  D_PTR(const BaseDevice);
798  return d->deviceName == otherName;
799 }
800 
801 /* add message to queue
802  * N.B. don't put carriage control in msg, we take care of that.
803  */
804 void BaseDevice::checkMessage(XMLEle *root)
805 {
806  XMLAtt *ap;
807  ap = findXMLAtt(root, "message");
808 
809  if (ap)
810  doMessage(root);
811 }
812 
813 /* Store msg in queue */
814 void BaseDevice::doMessage(XMLEle *msg)
815 {
816  XMLAtt *message;
817  XMLAtt *time_stamp;
818 
819  char msgBuffer[MAXRBUF];
820 
821  /* prefix our timestamp if not with msg */
822  time_stamp = findXMLAtt(msg, "timestamp");
823 
824  /* finally! the msg */
825  message = findXMLAtt(msg, "message");
826  if (!message)
827  return;
828 
829  if (time_stamp)
830  snprintf(msgBuffer, MAXRBUF, "%s: %s ", valuXMLAtt(time_stamp), valuXMLAtt(message));
831  else
832  snprintf(msgBuffer, MAXRBUF, "%s: %s ", timestamp(), valuXMLAtt(message));
833 
834  std::string finalMsg = msgBuffer;
835 
836  // Prepend to the log
837  addMessage(finalMsg);
838 }
839 
840 void BaseDevice::addMessage(const std::string &msg)
841 {
842  D_PTR(BaseDevice);
843  std::unique_lock<std::mutex> guard(d->m_Lock);
844  d->messageLog.push_back(msg);
845  guard.unlock();
846 
847  if (d->mediator)
848  d->mediator->newMessage(this, d->messageLog.size() - 1);
849 }
850 
851 const std::string &BaseDevice::messageQueue(size_t index) const
852 {
853  D_PTR(const BaseDevice);
854  std::lock_guard<std::mutex> lock(d->m_Lock);
855  assert(index < d->messageLog.size());
856  return d->messageLog.at(index);
857 }
858 
859 const std::string &BaseDevice::lastMessage() const
860 {
861  D_PTR(const BaseDevice);
862  std::lock_guard<std::mutex> lock(d->m_Lock);
863  assert(d->messageLog.size() != 0);
864  return d->messageLog.back();
865 }
866 
867 void BaseDevice::registerProperty(void *p, INDI_PROPERTY_TYPE type)
868 {
869  D_PTR(BaseDevice);
870  if (p == nullptr || type == INDI_UNKNOWN)
871  return;
872 
873  const char *name = INDI::Property(p, type).getName();
874 
875  auto pContainer = getProperty(name, type);
876 
877  if (pContainer.isValid())
878  pContainer.setRegistered(true);
879  else
880  {
881  std::lock_guard<std::mutex> lock(d->m_Lock);
882  d->pAll.push_back(INDI::Property(p, type));
883  }
884 }
885 
886 void BaseDevice::registerProperty(INDI::Property &property)
887 {
888  D_PTR(BaseDevice);
889 
890  if (property.getType() == INDI_UNKNOWN)
891  return;
892 
893  auto pContainer = getProperty(property.getName(), property.getType());
894 
895  if (pContainer.isValid())
896  pContainer.setRegistered(true);
897  else
898  {
899  std::lock_guard<std::mutex> lock(d->m_Lock);
900  d->pAll.push_back(property);
901  }
902 }
903 
904 const char *BaseDevice::getDriverName() const
905 {
906  auto driverInfo = getText("DRIVER_INFO");
907 
908  if (!driverInfo)
909  return nullptr;
910 
911  auto driverName = driverInfo->findWidgetByName("DRIVER_NAME");
912 
913  return driverName ? driverName->getText() : nullptr;
914 }
915 
916 
917 void BaseDevice::registerProperty(ITextVectorProperty *property)
918 {
919  registerProperty(property, INDI_TEXT);
920 }
921 
922 void BaseDevice::registerProperty(INumberVectorProperty *property)
923 {
924  registerProperty(property, INDI_NUMBER);
925 }
926 
927 void BaseDevice::registerProperty(ISwitchVectorProperty *property)
928 {
929  registerProperty(property, INDI_SWITCH);
930 }
931 
932 void BaseDevice::registerProperty(ILightVectorProperty *property)
933 {
934  registerProperty(property, INDI_LIGHT);
935 }
936 
937 void BaseDevice::registerProperty(IBLOBVectorProperty *property)
938 {
939  registerProperty(property, INDI_BLOB);
940 }
941 
942 void BaseDevice::registerProperty(PropertyView<IText> *property)
943 {
944  registerProperty(static_cast<ITextVectorProperty*>(property));
945 }
946 
947 void BaseDevice::registerProperty(PropertyView<INumber> *property)
948 {
949  registerProperty(static_cast<INumberVectorProperty*>(property));
950 }
951 
952 void BaseDevice::registerProperty(PropertyView<ISwitch> *property)
953 {
954  registerProperty(static_cast<ISwitchVectorProperty*>(property));
955 }
956 
957 void BaseDevice::registerProperty(PropertyView<ILight> *property)
958 {
959  BaseDevice::registerProperty(static_cast<ILightVectorProperty*>(property));
960 }
961 
962 void BaseDevice::registerProperty(PropertyView<IBLOB> *property)
963 {
964  BaseDevice::registerProperty(static_cast<IBLOBVectorProperty*>(property));
965 }
966 
967 const char *BaseDevice::getDriverExec() const
968 {
969  auto driverInfo = getText("DRIVER_INFO");
970 
971  if (!driverInfo)
972  return nullptr;
973 
974  auto driverExec = driverInfo->findWidgetByName("DRIVER_EXEC");
975 
976  return driverExec ? driverExec->getText() : nullptr;
977 }
978 
979 const char *BaseDevice::getDriverVersion() const
980 {
981  auto driverInfo = getText("DRIVER_INFO");
982 
983  if (!driverInfo)
984  return nullptr;
985 
986  auto driverVersion = driverInfo->findWidgetByName("DRIVER_VERSION");
987 
988  return driverVersion ? driverVersion->getText() : nullptr;
989 }
990 
991 uint16_t BaseDevice::getDriverInterface()
992 {
993  auto driverInfo = getText("DRIVER_INFO");
994 
995  if (!driverInfo)
996  return 0;
997 
998  auto driverInterface = driverInfo->findWidgetByName("DRIVER_INTERFACE");
999 
1000  return driverInterface ? atoi(driverInterface->getText()) : 0;
1001 }
1002 
1003 void BaseDevice::setMediator(INDI::BaseMediator *mediator)
1004 {
1005  D_PTR(BaseDevice);
1006  d->mediator = mediator;
1008 
1009 INDI::BaseMediator *BaseDevice::getMediator() const
1010 {
1011  D_PTR(const BaseDevice);
1012  return d->mediator;
1013 }
1014 
1015 }
1016 
1017 #if defined(_MSC_VER)
1018 #undef snprintf
1019 #pragma warning(pop)
1020 #endif
INDI_UNKNOWN
@ INDI_UNKNOWN
Definition: indidriver.c:62
INDI::WidgetView< IText >::setParent
void setParent(ITextVectorProperty *parent)
Definition: indipropertyview.h:272
crackIPState
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indicom.c:1211
INDI_BLOB
@ INDI_BLOB
Definition: indidriver.c:61
INDI::BaseDevice::getProperties
Properties getProperties()
Return a list of all properties in the device.
Definition: basedevice.cpp:168
indipropertytext.h
indipropertynumber.h
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::BaseDevice::getText
INDI::PropertyView< IText > * getText(const char *name) const
Definition: basedevice.cpp:104
INDI::PropertyText
Definition: indipropertytext.h:27
indistandardproperty.h
indipropertyblob.h
INDI::WidgetView< INumber >::setFormat
void setFormat(const char *format)
Definition: indipropertyview.h:337
newLilXML
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.c:148
basedevice.h
IPState
IPState
Property state.
Definition: indiapi.h:158
INDI::WidgetView< ILight >::setParent
void setParent(ILightVectorProperty *parent)
Definition: indipropertyview.h:452
INDI::WidgetView< ILight >::setLabel
void setLabel(const char *label)
Definition: indipropertyview.h:458
INDI::Property::getName
const char * getName() const
Definition: indiproperty.cpp:289
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
crackISState
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indicom.c:1229
INDI::WidgetView< INumber >::setName
void setName(const char *name)
Definition: indipropertyview.h:331
_ILightVectorProperty
Light vector property descriptor.
Definition: indiapi.h:415
INDI::Property::setGroupName
void setGroupName(const char *groupName)
Definition: indiproperty.cpp:253
INDI::WidgetView< ILight >
Definition: indipropertyview.h:436
pcdataXMLEle
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:575
indicom.h
Implementations for common driver routines.
indipropertyswitch.h
INDI::BaseDevicePrivate
Definition: basedevice_p.h:48
locale_compat.h
INDI::Property::getProperty
void * getProperty() const
Definition: indiproperty.cpp:197
nextXMLEle
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:524
INDI::WidgetView< IText >::setText
void setText(const char *text, size_t size)
Definition: indipropertyview.h:282
f_scansexa
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:195
INDI::PropertyLight
Definition: indipropertylight.h:27
INDI::BaseDevice::BaseDevice
BaseDevice()
Definition: basedevice.cpp:88
_IBLOBVectorProperty
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:469
INDI::BaseDevice::getBLOB
INDI::PropertyView< IBLOB > * getBLOB(const char *name) const
Definition: basedevice.cpp:119
INDI::PropertySwitch
Definition: indipropertyswitch.h:27
INDI::BaseDevice::getNumber
INDI::PropertyView< INumber > * getNumber(const char *name) const
Definition: basedevice.cpp:99
timestamp
const char * timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Definition: indicom.c:334
IUFindBLOB
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition: indicom.c:1381
Pulsar2Commands::getDeviceName
const char * getDeviceName()
Definition: lx200pulsar2.cpp:454
INDI::WidgetView< INumber >::setMin
void setMin(double min)
Definition: indipropertyview.h:340
INDI::Properties
Definition: indiproperties.h:31
INDI_PROPERTY_TYPE
INDI_PROPERTY_TYPE
Definition: indibasetypes.h:22
INDI::BaseDevice::~BaseDevice
virtual ~BaseDevice()
Definition: basedevice.cpp:92
INDI::WidgetView< IText >::getName
const char * getName() const
Definition: indipropertyview.h:290
INDI::Property::setBaseDevice
void setBaseDevice(BaseDevice *idp)
Definition: indiproperty.cpp:191
INDI::WidgetView< IBLOB >::setFormat
void setFormat(const char *format)
Definition: indipropertyview.h:518
INDI::BaseDevice::getSwitch
INDI::PropertyView< ISwitch > * getSwitch(const char *name) const
Definition: basedevice.cpp:109
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
INDI::PropertySwitch::setRule
void setRule(ISRule rule)
Definition: indipropertyswitch.cpp:73
IDLog
void void void void void IDLog(const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(1
Function Drivers call to log a message locally.
INDI::Property::isValid
bool isValid() const
Definition: indiproperty.cpp:350
INDI::Property
Provides generic container for INDI properties.
Definition: indiproperty.h:43
_ITextVectorProperty
Text vector property descriptor.
Definition: indiapi.h:244
INDI::BaseDevice::getProperty
Property getProperty(const char *name, INDI_PROPERTY_TYPE type=INDI_UNKNOWN) const
Return a property and its type given its name.
Definition: basedevice.cpp:148
INDI::Property::setLabel
void setLabel(const char *label)
Definition: indiproperty.cpp:247
pcdatalenXMLEle
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition: lilxml.c:581
INDI::WidgetView< INumber >::setValue
void setValue(double value)
Definition: indipropertyview.h:344
INDI::WidgetView< IBLOB >::setParent
void setParent(IBLOBVectorProperty *parent)
Definition: indipropertyview.h:509
type
__le16 type
Definition: pwc-ioctl.h:2
INDI::WidgetView< INumber >::setMax
void setMax(double max)
Definition: indipropertyview.h:341
INDI::WidgetView< INumber >::setStep
void setStep(double step)
Definition: indipropertyview.h:343
crackISRule
int crackISRule(const char *str, ISRule *ip)
Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string.
Definition: indicom.c:1253
_INumberVectorProperty
Number vector property descriptor.
Definition: indiapi.h:317
delLilXML
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.c:157
INDI::Property::setState
void setState(IPState state)
Definition: indiproperty.cpp:271
INDI::BaseDevicePrivate::pAll
BaseDevice::Properties pAll
Definition: basedevice_p.h:72
INDI_NUMBER
@ INDI_NUMBER
Definition: indidriver.c:57
INDI_LIGHT
@ INDI_LIGHT
Definition: indidriver.c:60
INDI::BaseDevicePrivate::lp
LilXML * lp
Definition: basedevice_p.h:73
INDI::PropertyNumber
Definition: indipropertynumber.h:27
xml_att_
Definition: lilxml.c:120
INDI_TEXT
@ INDI_TEXT
Definition: indidriver.c:59
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
base64.h
INDI::BaseDevicePrivate::deviceName
std::string deviceName
Definition: basedevice_p.h:71
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::Property::setDeviceName
void setDeviceName(const char *deviceName)
Definition: indiproperty.cpp:259
INDI::BaseMediator
Meditates event notification as generated by driver and passed to clients.
Definition: indibase.h:80
readXMLFile
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.c:622
INDI::WidgetView< IBLOB >
Definition: indipropertyview.h:493
tagXMLEle
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:569
xml_ele_
Definition: lilxml.c:105
INDI::WidgetView< INumber >::getName
const char * getName() const
Definition: indipropertyview.h:350
indipropertylight.h
INDI::BaseDevicePrivate::~BaseDevicePrivate
virtual ~BaseDevicePrivate()
Definition: basedevice.cpp:82
IPerm
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:181
MAXINDIFORMAT
#define MAXINDIFORMAT
Definition: indiapi.h:194
INDI::WidgetView< ISwitch >
Definition: indipropertyview.h:379
INDI::WidgetView< ISwitch >::getState
ISState getState() const
Definition: indipropertyview.h:414
INDI::PropertyView< INumber >
INDI::WidgetView< ILight >::setName
void setName(const char *name)
Definition: indipropertyview.h:455
crackIPerm
int crackIPerm(const char *str, IPerm *ip)
Extract property permission state (RW, RO, WO) from the supplied string.
Definition: indicom.c:1240
INDI::BaseDevice::INDI_PROPERTY_INVALID
@ INDI_PROPERTY_INVALID
Definition: basedevice.h:56
INDI::Property::isNameMatch
bool isNameMatch(const char *otherName) const
Definition: indiproperty.cpp:356
INDI::Property::setTimeout
void setTimeout(double timeout)
Definition: indiproperty.cpp:283
INDI::WidgetView< ISwitch >::getName
const char * getName() const
Definition: indipropertyview.h:411
INDI::BaseDevice::removeProperty
int removeProperty(const char *name, char *errmsg)
Remove a property.
Definition: basedevice.cpp:180
INDI::BaseDevice::getRawProperty
void * getRawProperty(const char *name, INDI_PROPERTY_TYPE type=INDI_UNKNOWN) const
Return a property and its type given its name.
Definition: basedevice.cpp:142
INDI::Property::getType
INDI_PROPERTY_TYPE getType() const
Definition: indiproperty.cpp:203
INDI::WidgetView< ILight >::setState
void setState(const IPState &state)
Definition: indipropertyview.h:461
INDI_SWITCH
@ INDI_SWITCH
Definition: indidriver.c:58
valuXMLAtt
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:593
INDI::WidgetView< IBLOB >::getName
const char * getName() const
Definition: indipropertyview.h:529
INDI::WidgetView< ISwitch >::setState
void setState(const ISState &state)
Definition: indipropertyview.h:404
INDI::WidgetView< IBLOB >::setLabel
void setLabel(const char *label)
Definition: indipropertyview.h:515
INDI::WidgetView< INumber >::setParent
void setParent(INumberVectorProperty *parent)
Definition: indipropertyview.h:328
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
INDI::WidgetView< IText >::setName
void setName(const char *name)
Definition: indipropertyview.h:275
INDI::WidgetView< ILight >::getName
const char * getName() const
Definition: indipropertyview.h:468
INDI::WidgetView< ISwitch >::setLabel
void setLabel(const char *label)
Definition: indipropertyview.h:401
INDI::WidgetView< ISwitch >::setParent
void setParent(ISwitchVectorProperty *parent)
Definition: indipropertyview.h:395
INDI::WidgetView< IBLOB >::setName
void setName(const char *name)
Definition: indipropertyview.h:512
findXMLAttValu
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:613
INDI::BaseDevice::getPropertyPermission
IPerm getPropertyPermission(const char *name) const
Definition: basedevice.cpp:133
ISState
ISState
Switch state.
Definition: indiapi.h:148
INDI::BaseDevice::getPropertyState
IPState getPropertyState(const char *name) const
Definition: basedevice.cpp:124
INDI::WidgetView< ISwitch >::setName
void setName(const char *name)
Definition: indipropertyview.h:398
basedevice_p.h
INDI::SP::CONNECTION
const char * CONNECTION
Connect to and disconnect from device.
Definition: indistandardproperty.cpp:63
ISRule
ISRule
Switch vector rule hint.
Definition: indiapi.h:170
INDI::Property::isEmpty
bool isEmpty() const
Definition: indiproperty.cpp:343
INDI::WidgetView< IText >::setLabel
void setLabel(const char *label)
Definition: indipropertyview.h:278
INDI::WidgetView< IText >
Definition: indipropertyview.h:256
INDI_PROPERTY_DUPLICATED
@ INDI_PROPERTY_DUPLICATED
Definition: indibasetypes.h:59
INDI::WidgetView< INumber >::setLabel
void setLabel(const char *label)
Definition: indipropertyview.h:334
INDI::Property::setPermission
void setPermission(IPerm permission)
Definition: indiproperty.cpp:277
from64tobits_fast
int from64tobits_fast(char *out, const char *in, int inlen)
Definition: base64.c:106
INDI::BaseDevice::Properties
INDI::Properties Properties
Definition: basedevice.h:49
delXMLEle
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.c:165
INDI::WidgetView< INumber >
Definition: indipropertyview.h:312
errno
int errno
INDI::BaseDevice
Class to provide basic INDI device functionality.
Definition: basedevice.h:45
IBLOB
One Blob (Binary Large Object) descriptor.
crackDN
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indicom.c:1317
INDI::BaseDevicePrivate::BaseDevicePrivate
BaseDevicePrivate()
Definition: basedevice.cpp:70
INDI::BaseDevice::getLight
INDI::PropertyView< ILight > * getLight(const char *name) const
Definition: basedevice.cpp:114
findXMLAtt
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:493
_ISwitchVectorProperty
Switch vector property descriptor.
Definition: indiapi.h:365
INDI::PropertyBlob
Definition: indipropertyblob.h:27
INDI::Property::setName
void setName(const char *name)
Definition: indiproperty.cpp:241
ISS_ON
@ ISS_ON
Definition: indiapi.h:151
INDI::Properties::clear
void clear()
Definition: indiproperties.cpp:53