Instrument Neutral Distributed Interface INDI  2.0.2
defaultdevice.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 "defaultdevice.h"
20 #include "defaultdevice_p.h"
21 
22 #include "indicom.h"
23 #include "indiapi.h"
24 
25 #include "indistandardproperty.h"
27 
28 #include "indipropertyswitch.h"
29 #include "indipropertytext.h"
30 #include "indipropertynumber.h"
31 #include "indipropertyblob.h"
32 
33 #include <cstdlib>
34 #include <cstring>
35 #include <assert.h>
36 #include <algorithm>
37 
38 const char *COMMUNICATION_TAB = "Communication";
39 const char *MAIN_CONTROL_TAB = "Main Control";
40 const char *CONNECTION_TAB = "Connection";
41 const char *MOTION_TAB = "Motion Control";
42 const char *DATETIME_TAB = "Date/Time";
43 const char *SITE_TAB = "Site Management";
44 const char *OPTIONS_TAB = "Options";
45 const char *FILTER_TAB = "Filter Wheel";
46 const char *FOCUS_TAB = "Focuser";
47 const char *GUIDE_TAB = "Guide";
48 const char *ALIGNMENT_TAB = "Alignment";
49 const char *SATELLITE_TAB = "Satellite";
50 const char *INFO_TAB = "General Info";
51 
52 std::list<INDI::DefaultDevicePrivate*> INDI::DefaultDevicePrivate::devices;
53 std::recursive_mutex INDI::DefaultDevicePrivate::devicesLock;
54 
55 extern "C"
56 {
57 
58  void ISGetProperties(const char *dev)
59  {
60  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
62  it->defaultDevice->ISGetProperties(dev);
63  }
64 
65  void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
66  {
67  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
69  if (dev == nullptr || strcmp(dev, it->defaultDevice->getDeviceName()) == 0)
70  it->defaultDevice->ISNewSwitch(dev, name, states, names, n);
71  }
72 
73  void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
74  {
75  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
77  if (dev == nullptr || strcmp(dev, it->defaultDevice->getDeviceName()) == 0)
78  it->defaultDevice->ISNewNumber(dev, name, values, names, n);
79  }
80 
81  void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
82  {
83  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
85  if (dev == nullptr || strcmp(dev, it->defaultDevice->getDeviceName()) == 0)
86  it->defaultDevice->ISNewText(dev, name, texts, names, n);
87  }
88 
89  void ISNewBLOB(const char *dev, const char *name,
90  int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n
91  )
92  {
93  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
95  if (dev == nullptr || strcmp(dev, it->defaultDevice->getDeviceName()) == 0)
96  it->defaultDevice->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
97  }
98 
99  void ISSnoopDevice(XMLEle *root)
100  {
101  const std::unique_lock<std::recursive_mutex> lock(INDI::DefaultDevicePrivate::devicesLock);
103  it->defaultDevice->ISSnoopDevice(root);
104  }
105 
106 } // extern "C"
107 
108 
109 // For drivers, indiproperty need access to ID/IU functions
110 extern void (*WeakIDSetTextVA)(const ITextVectorProperty *, const char *, va_list);
111 extern void (*WeakIDDefTextVA)(const ITextVectorProperty *, const char *, va_list);
112 extern void (*WeakIDSetNumberVA)(const INumberVectorProperty *, const char *, va_list);
113 extern void (*WeakIDDefNumberVA)(const INumberVectorProperty *, const char *, va_list);
114 extern void (*WeakIDSetSwitchVA)(const ISwitchVectorProperty *, const char *, va_list);
115 extern void (*WeakIDDefSwitchVA)(const ISwitchVectorProperty *, const char *, va_list);
116 extern void (*WeakIDSetLightVA)(const ILightVectorProperty *, const char *, va_list);
117 extern void (*WeakIDDefLightVA)(const ILightVectorProperty *, const char *, va_list);
118 extern void (*WeakIDSetBLOBVA)(const IBLOBVectorProperty *, const char *, va_list);
119 extern void (*WeakIDDefBLOBVA)(const IBLOBVectorProperty *, const char *, va_list);
120 extern int (*WeakIUUpdateText)(ITextVectorProperty *, char *[], char *[], int);
121 extern int (*WeakIUUpdateNumber)(INumberVectorProperty *, double[], char *[], int n);
122 extern int (*WeakIUUpdateSwitch)(ISwitchVectorProperty *, ISState *, char *[], int n);
123 extern int (*WeakIUUpdateBLOB)(IBLOBVectorProperty *, int [], int [], char *[], char *[], char *[], int n);
124 extern void (*WeakIUUpdateMinMax)(const INumberVectorProperty *);
125 
126 static struct WeakIDLoader
127 {
128  WeakIDLoader()
129  {
145  }
146 } weakLoader;
147 
148 void timerfunc(void *t)
149 {
150  INDI::DefaultDevice *devPtr = static_cast<INDI::DefaultDevice *>(t);
151  if (devPtr != nullptr)
152  {
153  // this was for my device
154  // but we dont have a way of telling
155  // WHICH timer was hit :(
156  devPtr->TimerHit();
157  }
158  return;
159 }
160 
161 
162 namespace INDI
163 {
164 
166  : defaultDevice(defaultDevice)
167 {
168  const std::unique_lock<std::recursive_mutex> lock(DefaultDevicePrivate::devicesLock);
169  devices.push_back(this);
170 }
171 
173 {
174  const std::unique_lock<std::recursive_mutex> lock(DefaultDevicePrivate::devicesLock);
175  devices.remove(this);
176 }
177 
179  : ParentDevice(std::shared_ptr<ParentDevicePrivate>(new DefaultDevicePrivate(this)))
180 {
181  D_PTR(DefaultDevice);
182  d->m_MainLoopTimer.setSingleShot(true);
183  d->m_MainLoopTimer.setInterval(getPollingPeriod());
184  d->m_MainLoopTimer.callOnTimeout(std::bind(&DefaultDevice::TimerHit, this));
185 }
186 
188 {
189  return loadConfig(true, property.getName());
190 }
191 
192 bool DefaultDevice::loadConfig(bool silent, const char *property)
193 {
194  D_PTR(DefaultDevice);
195  char errmsg[MAXRBUF] = {0};
196  d->isConfigLoading = true;
197  bool pResult = IUReadConfig(nullptr, getDeviceName(), property, silent ? 1 : 0, errmsg) == 0 ? true : false;
198  d->isConfigLoading = false;
199 
200  if (!silent)
201  {
202  if (pResult)
203  {
204  LOG_DEBUG("Configuration successfully loaded.");
205  }
206  else
207  LOG_INFO("No previous configuration found. To save driver configuration, click Save Configuration in Options tab.");
208  }
209 
210  // Determine default config file name
211  // Need to be done only once per device.
212  if (d->isDefaultConfigLoaded == false)
213  {
214  d->isDefaultConfigLoaded = IUSaveDefaultConfig(nullptr, nullptr, getDeviceName()) == 0;
215  }
216 
217  return pResult;
218 }
219 
221 {
222  D_PTR(DefaultDevice);
223  d->DebugSP.save(fp);
224  d->PollPeriodNP.save(fp);
225  if (!d->ConnectionModeSP.isEmpty())
226  d->ConnectionModeSP.save(fp);
227 
228  if (d->activeConnection != nullptr)
229  d->activeConnection->saveConfigItems(fp);
230 
232 }
233 
235 {
236  for (const auto &oneProperty : getProperties())
237  {
238  if (oneProperty.getType() == INDI_SWITCH)
239  {
240  const auto &svp = oneProperty.getSwitch();
241  /* Never save CONNECTION property. Don't save switches with no switches on if the rule is one of many */
242  if (
243  (svp->isNameMatch(INDI::SP::CONNECTION)) ||
244  (svp->getRule() == ISR_1OFMANY && svp->findOnSwitch() == nullptr)
245  )
246  continue;
247  }
248  oneProperty.save(fp);
249  }
250  return true;
251 }
252 
254 {
255  char errmsg[MAXRBUF];
256  if (IUPurgeConfig(nullptr, getDeviceName(), errmsg) == -1)
257  {
258  LOGF_WARN("%s", errmsg);
259  return false;
260  }
261 
262  LOG_INFO("Configuration file successfully purged.");
263  return true;
264 }
265 
267 {
268  return saveConfig(true, property.getName());
269 }
270 
271 bool DefaultDevice::saveConfig(bool silent, const char *property)
272 {
273  D_PTR(DefaultDevice);
274  silent = false;
275  char errmsg[MAXRBUF] = {0};
276 
277  FILE *fp = nullptr;
278 
279  if (property == nullptr)
280  {
281  fp = IUGetConfigFP(nullptr, getDeviceName(), "w", errmsg);
282 
283  if (fp == nullptr)
284  {
285  if (!silent)
286  LOGF_WARN("Failed to save configuration. %s", errmsg);
287  return false;
288  }
289 
290  IUSaveConfigTag(fp, 0, getDeviceName(), silent ? 1 : 0);
291 
292  saveConfigItems(fp);
293 
294  IUSaveConfigTag(fp, 1, getDeviceName(), silent ? 1 : 0);
295 
296  fflush(fp);
297  fclose(fp);
298 
299  if (d->isDefaultConfigLoaded == false)
300  {
301  d->isDefaultConfigLoaded = IUSaveDefaultConfig(nullptr, nullptr, getDeviceName()) == 0;
302  }
303 
304  LOG_DEBUG("Configuration successfully saved.");
305  }
306  else
307  {
308  fp = IUGetConfigFP(nullptr, getDeviceName(), "r", errmsg);
309 
310  if (fp == nullptr)
311  {
312  //if (!silent)
313  // LOGF_ERROR("Error saving configuration. %s", errmsg);
314  //return false;
315  // If we don't have an existing file pointer, save all properties.
316  return saveConfig(silent);
317  }
318 
319  LilXML *lp = newLilXML();
320  XMLEle *root = readXMLFile(fp, lp, errmsg);
321 
322  fclose(fp);
323  delLilXML(lp);
324 
325  if (root == nullptr)
326  return false;
327 
328  XMLEle *ep = nullptr;
329  bool propertySaved = false;
330 
331  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
332  {
333  const char *elemName = findXMLAttValu(ep, "name");
334  const char *tagName = tagXMLEle(ep);
335 
336  if (strcmp(elemName, property))
337  continue;
338 
339  if (!strcmp(tagName, "newSwitchVector"))
340  {
341  auto svp = getSwitch(elemName);
342  if (!svp)
343  {
344  delXMLEle(root);
345  return false;
346  }
347 
348  XMLEle *sw = nullptr;
349  for (sw = nextXMLEle(ep, 1); sw != nullptr; sw = nextXMLEle(ep, 0))
350  {
351  auto oneSwitch = svp.findWidgetByName(findXMLAttValu(sw, "name"));
352  if (!oneSwitch)
353  {
354  delXMLEle(root);
355  return false;
356  }
357  char formatString[MAXRBUF];
358  snprintf(formatString, MAXRBUF, " %s\n", oneSwitch->getStateAsString());
359  editXMLEle(sw, formatString);
360  }
361 
362  propertySaved = true;
363  break;
364  }
365  else if (!strcmp(tagName, "newNumberVector"))
366  {
367  auto nvp = getNumber(elemName);
368  if (!nvp)
369  {
370  delXMLEle(root);
371  return false;
372  }
373 
374  XMLEle *np = nullptr;
375  for (np = nextXMLEle(ep, 1); np != nullptr; np = nextXMLEle(ep, 0))
376  {
377  auto oneNumber = nvp.findWidgetByName(findXMLAttValu(np, "name"));
378  if (!oneNumber)
379  return false;
380 
381  char formatString[MAXRBUF];
382  snprintf(formatString, MAXRBUF, " %.20g\n", oneNumber->getValue());
383  editXMLEle(np, formatString);
384  }
385 
386  propertySaved = true;
387  break;
388  }
389  else if (!strcmp(tagName, "newTextVector"))
390  {
391  auto tvp = getText(elemName);
392  if (!tvp)
393  {
394  delXMLEle(root);
395  return false;
396  }
397 
398  XMLEle *tp = nullptr;
399  for (tp = nextXMLEle(ep, 1); tp != nullptr; tp = nextXMLEle(ep, 0))
400  {
401  auto oneText = tvp.findWidgetByName(findXMLAttValu(tp, "name"));
402  if (!oneText)
403  return false;
404 
405  char formatString[MAXRBUF];
406  snprintf(formatString, MAXRBUF, " %s\n", oneText->getText() ? oneText->getText() : "");
407  editXMLEle(tp, formatString);
408  }
409 
410  propertySaved = true;
411  break;
412  }
413  }
414 
415  if (propertySaved)
416  {
417  fp = IUGetConfigFP(nullptr, getDeviceName(), "w", errmsg);
418  prXMLEle(fp, root, 0);
419  fflush(fp);
420  fclose(fp);
421  delXMLEle(root);
422  LOGF_DEBUG("Configuration successfully saved for %s.", property);
423  return true;
424  }
425  else
426  {
427  delXMLEle(root);
428  // If property does not exist, save the whole thing
429  return saveConfig(silent);
430  }
431  }
432 
433  return true;
434 }
435 
437 {
438  char configDefaultFileName[MAXRBUF];
439  char errmsg[MAXRBUF];
440  bool pResult = false;
441 
442  if (getenv("INDICONFIG"))
443  snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
444  else
445  snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), getDeviceName());
446 
447  LOGF_DEBUG("Requesting to load default config with: %s", configDefaultFileName);
448 
449  pResult = IUReadConfig(configDefaultFileName, getDeviceName(), nullptr, 0, errmsg) == 0 ? true : false;
450 
451  if (pResult)
452  LOG_INFO("Default configuration loaded.");
453  else
454  LOGF_INFO("Error loading default configuraiton. %s", errmsg);
455 
456  return pResult;
457 }
458 
459 bool DefaultDevice::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
460 {
461  D_PTR(DefaultDevice);
462  // ignore if not ours //
463  if (strcmp(dev, getDeviceName()))
464  return false;
465 
466  INDI::PropertySwitch property = getProperty(name, INDI_SWITCH);
467 
468  if (!property.isValid())
469  return false;
470 
471  // #PS: TODO Remove
473  // Debugging and Logging Levels
475  if (
476  property.isNameMatch("DEBUG_LEVEL") ||
477  property.isNameMatch("LOGGING_LEVEL") ||
478  property.isNameMatch("LOG_OUTPUT"))
479  {
480  bool rc = Logger::ISNewSwitch(dev, name, states, names, n);
481 
482  if (property.isNameMatch("LOG_OUTPUT"))
483  {
484  auto sw = property.findWidgetByName("FILE_DEBUG");
485  if (sw != nullptr && sw->getState() == ISS_ON)
486  DEBUGF(Logger::DBG_SESSION, "Session log file %s", Logger::getLogFile().c_str());
487  }
488 
489  return rc;
490  }
491 
492  property.update(states, names, n); // update and callback
493  if (property.hasUpdateCallback())
494  return true;
495 
496  bool rc = false;
497  for (Connection::Interface *oneConnection : d->connections)
498  rc |= oneConnection->ISNewSwitch(dev, name, states, names, n);
499 
500  return rc;
501 }
502 
503 bool DefaultDevice::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
504 {
505  D_PTR(DefaultDevice);
506 
507  INDI::PropertyNumber property = getProperty(name, INDI_NUMBER);
508 
509  if (!property.isValid())
510  return false;
511 
512  property.update(values, names, n); // update and callback
513  if (property.hasUpdateCallback())
514  return true;
515 
516  for (Connection::Interface *oneConnection : d->connections)
517  oneConnection->ISNewNumber(dev, name, values, names, n);
518 
519  return false;
520 }
521 
522 bool DefaultDevice::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
523 {
524  D_PTR(DefaultDevice);
525 
526  INDI::PropertyText property = getProperty(name, INDI_TEXT);
527 
528  if (!property.isValid())
529  return false;
530 
531  property.update(texts, names, n); // update and callback
532  if (property.hasUpdateCallback())
533  return true;
534 
535  for (Connection::Interface *oneConnection : d->connections)
536  oneConnection->ISNewText(dev, name, texts, names, n);
537 
538  return false;
539 }
540 
541 bool DefaultDevice::ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[],
542  char *formats[], char *names[], int n)
543 {
544  D_PTR(DefaultDevice);
545 
546  INDI::PropertyBlob property = getProperty(name, INDI_BLOB);
547 
548  if (!property.isValid())
549  return false;
550 
551  property.update(sizes, blobsizes, blobs, formats, names, n); // update and callback
552  if (property.hasUpdateCallback())
553  return true;
554 
555  for (Connection::Interface *oneConnection : d->connections)
556  oneConnection->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
557 
558  return false;
559 }
560 
562 {
563  D_PTR(DefaultDevice);
564  char errmsg[MAXRBUF];
565  return d->watchDevice.processXml(INDI::LilXmlElement(root), errmsg) < 0;
566 }
567 
568 void DefaultDevice::watchDevice(const char *name, const std::function<void (BaseDevice)> &callback)
569 {
570  D_PTR(DefaultDevice);
571  d->watchDevice.watchDevice(name, callback);
572  IDSnoopDevice(name, nullptr);
573 }
574 
576 {
577  D_PTR(DefaultDevice);
578  registerProperty(d->DebugSP);
579  d->isDebug = false;
580 }
581 
583 {
584  D_PTR(DefaultDevice);
585  registerProperty(d->SimulationSP);
586  d->isSimulation = false;
587 }
588 
590 {
591  D_PTR(DefaultDevice);
592  registerProperty(d->ConfigProcessSP);
593 }
594 
596 {
597  D_PTR(DefaultDevice);
598  registerProperty(d->PollPeriodNP);
599 }
600 
602 {
603  addDebugControl();
607 }
608 
609 void DefaultDevice::setDebug(bool enable)
610 {
611  D_PTR(DefaultDevice);
612  if (d->isDebug == enable)
613  {
614  d->DebugSP.setState(IPS_OK);
615  d->DebugSP.apply();
616  return;
617  }
618 
619  d->DebugSP.reset();
620 
621  auto sp = d->DebugSP.findWidgetByName(enable ? "ENABLE" : "DISABLE");
622  if (sp)
623  {
624  sp->setState(ISS_ON);
625  LOGF_INFO("Debug is %s.", enable ? "enabled" : "disabled");
626  }
627 
628  d->isDebug = enable;
629 
630  // Inform logger
631  if (Logger::updateProperties(enable) == false)
632  DEBUG(Logger::DBG_WARNING, "setLogDebug: Logger error");
633 
634  debugTriggered(enable);
635  d->DebugSP.setState(IPS_OK);
636  d->DebugSP.apply();
637 }
638 
640 {
641  D_PTR(DefaultDevice);
642  if (d->isSimulation == enable)
643  {
644  d->SimulationSP.setState(IPS_OK);
645  d->SimulationSP.apply();
646  return;
647  }
648 
649  d->SimulationSP.reset();
650 
651  auto sp = d->SimulationSP.findWidgetByName(enable ? "ENABLE" : "DISABLE");
652  if (sp)
653  {
654  LOGF_INFO("Simulation is %s.", enable ? "enabled" : "disabled");
655  sp->setState(ISS_ON);
656  }
657 
658  d->isSimulation = enable;
659  simulationTriggered(enable);
660  d->SimulationSP.setState(IPS_OK);
661  d->SimulationSP.apply();
662 }
663 
665 {
666  D_PTR(const DefaultDevice);
667  return d->isDebug;
668 }
669 
671 {
672  D_PTR(const DefaultDevice);
673  return d->isSimulation;
674 }
675 
677 {
678  INDI_UNUSED(enable);
679 }
680 
682 {
683  INDI_UNUSED(enable);
684 }
685 
686 void DefaultDevice::ISGetProperties(const char *dev)
687 {
688  D_PTR(DefaultDevice);
689  if (d->isInit == false)
690  {
691  if (dev != nullptr)
692  setDeviceName(dev);
693  else if (*getDeviceName() == '\0')
694  {
695  char *envDev = getenv("INDIDEV");
696  if (envDev != nullptr)
697  setDeviceName(envDev);
698  else
700  }
701 
702  d->ConnectionSP.setDeviceName(getDeviceName());
703  initProperties();
705 
706  // If we have no connections, move Driver Info to General Info tab
707  if (d->connections.size() == 0)
708  d->DriverInfoTP.setGroupName(INFO_TAB);
709  }
710 
711  for (const auto &oneProperty : *getProperties())
712  {
713  if (d->defineDynamicProperties == false && oneProperty.isDynamic())
714  continue;
715 
716  oneProperty.define();
717  }
718 
719  // Remember debug & logging settings
720  if (d->isInit == false)
721  {
722  loadConfig(true, "DEBUG");
723  loadConfig(true, "DEBUG_LEVEL");
724  loadConfig(true, "LOGGING_LEVEL");
725  loadConfig(true, "POLLING_PERIOD");
726  loadConfig(true, "LOG_OUTPUT");
727  }
728 
729  if (d->ConnectionModeSP.isEmpty())
730  {
731  if (d->connections.size() > 0)
732  {
733  d->ConnectionModeSP.resize(d->connections.size());
734  auto sp = &d->ConnectionModeSP[0];
735  for (Connection::Interface *oneConnection : d->connections)
736  {
737  (sp++)->fill(oneConnection->name(), oneConnection->label(), ISS_OFF);
738  }
739  d->ConnectionModeSP.fill(getDeviceName(), "CONNECTION_MODE", "Connection Mode", CONNECTION_TAB, IP_RW, ISR_1OFMANY, 60,
740  IPS_IDLE);
741 
742  // Try to read config first
743  if (IUGetConfigOnSwitchIndex(getDeviceName(), d->ConnectionModeSP.getName(), &d->m_ConfigConnectionMode) == 0)
744  {
745  d->ConnectionModeSP[d->m_ConfigConnectionMode].setState(ISS_ON);
746  d->activeConnection = d->connections[d->m_ConfigConnectionMode];
747  }
748  // Check if we already have an active connection set.
749  else if (d->activeConnection != nullptr)
750  {
751  auto it = std::find(d->connections.begin(), d->connections.end(), d->activeConnection);
752  if (it != d->connections.end())
753  {
754  int index = std::distance(d->connections.begin(), it);
755  if (index >= 0)
756  d->ConnectionModeSP[index].setState(ISS_ON);
757  }
758  }
759  // Otherwise use connection 0
760  else
761  {
762  d->ConnectionModeSP[0].setState(ISS_ON);
763  d->activeConnection = d->connections[0];
764  }
765 
766  defineProperty(d->ConnectionModeSP);
767  d->activeConnection->Activated();
768  }
769  }
770 
771  d->isInit = true;
772 }
773 
775 {
776  for (auto &oneProperty : getProperties())
777  {
778  oneProperty.setState(IPS_IDLE);
779  oneProperty.apply();
780  }
781 }
782 
783 void DefaultDevice::setConnected(bool status, IPState state, const char *msg)
784 {
785  auto svp = getSwitch(INDI::SP::CONNECTION);
786  if (!svp)
787  return;
788 
789  svp[INDI_ENABLED].setState(status ? ISS_ON : ISS_OFF);
790  svp[INDI_DISABLED].setState(status ? ISS_OFF : ISS_ON);
791  svp.setState(state);
792 
793  if (msg == nullptr)
794  svp.apply();
795  else
796  svp.apply("%s", msg);
797 }
798 
799 // Set the timeout for the TimerHit function.
800 // This is a single shot timer.
801 int DefaultDevice::SetTimer(uint32_t ms)
802 {
803  D_PTR(DefaultDevice);
804  d->m_MainLoopTimer.start(ms);
805  return 1;
806 }
807 
808 // Remove main timer. ID is not used.
809 // Kept for backward compatiblity
811 {
812  INDI_UNUSED(id);
813  D_PTR(DefaultDevice);
814  d->m_MainLoopTimer.stop();
815  return;
816 }
817 
818 // This is just a placeholder
819 // This function should be overriden by child classes if they use timers
820 // So we should never get here
822 {
823  return;
824 }
825 
827 {
828  // The base device has no properties to update
829  return true;
830 }
831 
832 // Early access to properties.
833 // The `BaseDevice::getDriverInterface()` function will return a false value of 0
834 // when the `DriverInfoTP` property has not yet been registered.
835 //
836 // The situation occurs in the case of drivers where the class that inherits from `DefaultDevice`
837 // will call the `setDriverInterface` function in the constructor
838 
840 {
841  D_PTR(const DefaultDevice);
842  return atoi(d->DriverInfoTP[3 /* DRIVER_INTERFACE */].getText());
843 }
844 
846 {
847  D_PTR(DefaultDevice);
848  d->DriverInfoTP[3 /* DRIVER_INTERFACE */].setText(std::to_string(value));
849 }
850 
852 {
853  D_PTR(DefaultDevice);
854  d->DriverInfoTP.apply();
855 }
856 
858 {
859  D_PTR(DefaultDevice);
860  char versionStr[16];
861  char interfaceStr[16];
862 
863  snprintf(versionStr, 16, "%d.%d", d->majorVersion, d->minorVersion);
864  snprintf(interfaceStr, 16, "%d", getDriverInterface());
865 
866  // Connection Mode
867  d->ConnectionModeSP.onUpdate([d](){
868  int activeConnectionMode = d->ConnectionModeSP.findOnSwitchIndex();
869 
870  if (activeConnectionMode >= 0 && activeConnectionMode < static_cast<int>(d->connections.size()))
871  {
872  d->activeConnection = d->connections[activeConnectionMode];
873  d->activeConnection->Activated();
874 
875  for (Connection::Interface *oneConnection : d->connections)
876  {
877  if (oneConnection == d->activeConnection)
878  continue;
879 
880  oneConnection->Deactivated();
881  }
882 
883  d->ConnectionModeSP.setState(IPS_OK);
884  }
885  else
886  d->ConnectionModeSP.setState(IPS_ALERT);
887 
888  d->ConnectionModeSP.apply();
889 
890  });
891 
892  // Connection
893  d->ConnectionSP[INDI_ENABLED ].fill("CONNECT", "Connect", ISS_OFF);
894  d->ConnectionSP[INDI_DISABLED].fill("DISCONNECT", "Disconnect", ISS_ON);
895  d->ConnectionSP.fill(getDeviceName(), INDI::SP::CONNECTION, "Connection", "Main Control", IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
896  d->ConnectionSP.onNewValues([this](const INDI::PropertySwitch::NewValues &values)
897  {
898  if (values.contains("CONNECT", ISS_ON))
899  {
900  // If disconnected, try to connect.
901  if (isConnected() == false)
902  {
903  if (Connect())
904  {
905  // Connection is successful, set it to OK and updateProperties.
906  setConnected(true);
907  updateProperties();
908  }
909  else
910  setConnected(false, IPS_ALERT);
911  }
912  else
913  // Already connected, tell client we're connected already.
914  setConnected(true);
915  }
916 
917  if (values.contains("DISCONNECT", ISS_ON))
918  {
919  // If connected, try to disconnect.
920  if (isConnected() == true)
921  {
922  // Disconnection is successful, set it IDLE and updateProperties.
923  if (Disconnect())
924  {
925  setConnected(false, IPS_IDLE);
926  updateProperties();
927  }
928  else
929  setConnected(true, IPS_ALERT);
930  }
931  // Already disconnected, tell client we're disconnected already.
932  else
933  setConnected(false, IPS_IDLE);
934  }
935 
936  });
937  registerProperty(d->ConnectionSP);
938 
939  d->DriverInfoTP[0].fill("DRIVER_NAME", "Name", getDriverName());
940  d->DriverInfoTP[1].fill("DRIVER_EXEC", "Exec", getDriverExec());
941  d->DriverInfoTP[2].fill("DRIVER_VERSION", "Version", versionStr);
942  d->DriverInfoTP[3].fill("DRIVER_INTERFACE", "Interface", interfaceStr);
943  d->DriverInfoTP.fill(getDeviceName(), "DRIVER_INFO", "Driver Info", CONNECTION_TAB, IP_RO, 60, IPS_IDLE);
944  registerProperty(d->DriverInfoTP);
945 
946  // Debug
947  d->DebugSP[INDI_ENABLED ].fill("ENABLE", "Enable", ISS_OFF);
948  d->DebugSP[INDI_DISABLED].fill("DISABLE", "Disable", ISS_ON);
949  d->DebugSP.fill(getDeviceName(), "DEBUG", "Debug", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
950  d->DebugSP.onUpdate([this, d]()
951  {
952  auto sp = d->DebugSP.findOnSwitch();
953  assert(sp != nullptr);
954  setDebug(sp->isNameMatch("ENABLE") ? true : false);
955  });
956 
957  // Simulation
958  d->SimulationSP[INDI_ENABLED ].fill("ENABLE", "Enable", ISS_OFF);
959  d->SimulationSP[INDI_DISABLED].fill("DISABLE", "Disable", ISS_ON);
960  d->SimulationSP.fill(getDeviceName(), "SIMULATION", "Simulation", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
961  d->SimulationSP.onUpdate([this, d]()
962  {
963  auto sp = d->SimulationSP.findOnSwitch();
964  assert(sp != nullptr);
965  setSimulation(sp->isNameMatch("ENABLE") ? true : false);
966  });
967 
968  // Configuration
969  d->ConfigProcessSP[0].fill("CONFIG_LOAD", "Load", ISS_OFF);
970  d->ConfigProcessSP[1].fill("CONFIG_SAVE", "Save", ISS_OFF);
971  d->ConfigProcessSP[2].fill("CONFIG_DEFAULT", "Default", ISS_OFF);
972  d->ConfigProcessSP[3].fill("CONFIG_PURGE", "Purge", ISS_OFF);
973  d->ConfigProcessSP.fill(getDeviceName(), "CONFIG_PROCESS", "Configuration", "Options", IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
974  d->ConfigProcessSP.onUpdate([this, d]()
975  {
976  auto svp = d->ConfigProcessSP;
977  auto sp = svp.findOnSwitch();
978  svp.reset();
979  bool pResult = false;
980 
981  // Not suppose to happen (all switches off) but let's handle it anyway
982  if (sp == nullptr)
983  {
984  svp.setState(IPS_IDLE);
985  svp.apply();
986  return;
987  }
988 
989  if (sp->isNameMatch("CONFIG_LOAD"))
990  pResult = loadConfig();
991  else if (sp->isNameMatch("CONFIG_SAVE"))
992  pResult = saveConfig();
993  else if (sp->isNameMatch("CONFIG_DEFAULT"))
994  pResult = loadDefaultConfig();
995  else if (sp->isNameMatch("CONFIG_PURGE"))
996  pResult = purgeConfig();
997 
998  svp.setState(pResult ? IPS_OK : IPS_ALERT);
999  svp.apply();
1000  });
1001 
1002  // Polling Period
1003  d->PollPeriodNP[0].fill("PERIOD_MS", "Period (ms)", "%.f", 10, 600000, 1000, d->pollingPeriod);
1004  d->PollPeriodNP.fill(getDeviceName(), "POLLING_PERIOD", "Polling", "Options", IP_RW, 0, IPS_IDLE);
1005  d->PollPeriodNP.onUpdate([d]()
1006  {
1007  d->PollPeriodNP.setState(IPS_OK);
1008  d->pollingPeriod = static_cast<uint32_t>(d->PollPeriodNP[0].getValue());
1009  d->PollPeriodNP.apply();
1010  });
1011 
1013 
1014  // Ready the logger
1015  std::string logFile = getDriverExec();
1016 
1017  DEBUG_CONF(logFile, Logger::file_off | Logger::screen_on, Logger::defaultlevel, Logger::defaultlevel)
1018 
1019  return true;
1020 }
1021 
1022 bool DefaultDevice::deleteProperty(INDI::Property &property)
1023 {
1024  return deleteProperty(property.getName());
1025 }
1026 
1027 bool DefaultDevice::deleteProperty(const char *propertyName)
1028 {
1029  D_PTR(DefaultDevice);
1030  char errmsg[MAXRBUF];
1031 
1032  if (propertyName == nullptr)
1033  {
1034  //while(!pAll.empty()) delete bar.back(), bar.pop_back();
1035  IDDelete(getDeviceName(), nullptr, nullptr);
1036  return true;
1037  }
1038 
1039  // Keep dynamic properties in existing property list so they can be reused
1040  if (d->deleteDynamicProperties == false)
1041  {
1042  INDI::Property prop = getProperty(propertyName);
1043  if (prop && prop.isDynamic())
1044  {
1045  IDDelete(getDeviceName(), propertyName, nullptr);
1046  return true;
1047  }
1048  }
1049 
1050  if (removeProperty(propertyName, errmsg) == 0)
1051  {
1052  IDDelete(getDeviceName(), propertyName, nullptr);
1053  return true;
1054  }
1055  else
1056  return false;
1057 }
1058 
1059 void DefaultDevice::defineProperty(INumberVectorProperty *property)
1060 {
1061  registerProperty(INDI::Property(property));
1062  static_cast<PropertyViewNumber*>(property)->define();
1063 }
1064 
1065 void DefaultDevice::defineProperty(ITextVectorProperty *property)
1066 {
1067  registerProperty(INDI::Property(property));
1068  static_cast<PropertyViewText*>(property)->define();
1069 }
1070 
1071 void DefaultDevice::defineProperty(ISwitchVectorProperty *property)
1072 {
1073  registerProperty(INDI::Property(property));
1074  static_cast<PropertyViewSwitch*>(property)->define();
1075 }
1076 
1077 void DefaultDevice::defineProperty(ILightVectorProperty *property)
1078 {
1079  registerProperty(INDI::Property(property));
1080  static_cast<PropertyViewLight*>(property)->define();
1081 }
1082 
1083 void DefaultDevice::defineProperty(IBLOBVectorProperty *property)
1084 {
1085  registerProperty(INDI::Property(property));
1086  static_cast<PropertyViewBlob*>(property)->define();
1087 }
1088 
1089 void DefaultDevice::defineProperty(INDI::Property &property)
1090 {
1091  registerProperty(property);
1092  property.define();
1093 }
1094 
1095 void DefaultDevice::defineNumber(INumberVectorProperty *nvp)
1096 {
1097  defineProperty(nvp);
1098 }
1099 
1100 void DefaultDevice::defineText(ITextVectorProperty *tvp)
1101 {
1102  defineProperty(tvp);
1103 }
1104 
1105 void DefaultDevice::defineSwitch(ISwitchVectorProperty *svp)
1106 {
1107  defineProperty(svp);
1108 }
1109 
1110 void DefaultDevice::defineLight(ILightVectorProperty *lvp)
1111 {
1112  defineProperty(lvp);
1113 }
1114 
1115 void DefaultDevice::defineBLOB(IBLOBVectorProperty *bvp)
1116 {
1117  defineProperty(bvp);
1118 }
1119 
1120 bool DefaultDevice::Connect()
1121 {
1122  D_PTR(DefaultDevice);
1123  if (isConnected())
1124  return true;
1125 
1126  if (d->activeConnection == nullptr)
1127  {
1128  LOG_ERROR("No active connection defined.");
1129  return false;
1130  }
1131 
1132  bool rc = d->activeConnection->Connect();
1133 
1134  if (rc)
1135  {
1136  if (d->ConnectionModeSP.findOnSwitchIndex() != d->m_ConfigConnectionMode)
1137  saveConfig(true, d->ConnectionModeSP.getName());
1138  if (d->pollingPeriod > 0)
1139  SetTimer(d->pollingPeriod);
1140  }
1141 
1142  return rc;
1143 }
1144 
1145 bool DefaultDevice::Disconnect()
1146 {
1147  D_PTR(DefaultDevice);
1148  if (isSimulation())
1149  {
1150  DEBUGF(Logger::DBG_SESSION, "%s is offline.", getDeviceName());
1151  return true;
1152  }
1153 
1154  if (d->activeConnection)
1155  {
1156  bool rc = d->activeConnection->Disconnect();
1157  if (rc)
1158  {
1159  DEBUGF(Logger::DBG_SESSION, "%s is offline.", getDeviceName());
1160  return true;
1161  }
1162  else
1163  return false;
1164  }
1165 
1166  return false;
1167 }
1168 
1169 void DefaultDevice::registerConnection(Connection::Interface *newConnection)
1170 {
1171  D_PTR(DefaultDevice);
1172  d->connections.push_back(newConnection);
1173 }
1174 
1175 bool DefaultDevice::unRegisterConnection(Connection::Interface *existingConnection)
1176 {
1177  D_PTR(DefaultDevice);
1178 
1179  auto i = std::begin(d->connections);
1180 
1181  while (i != std::end(d->connections))
1182  {
1183  if (*i == existingConnection)
1184  {
1185  i = d->connections.erase(i);
1186  return true;
1187  }
1188  else
1189  ++i;
1190  }
1191 
1192  return false;
1193 }
1194 
1195 void DefaultDevice::setCurrentPollingPeriod(uint32_t msec)
1196 {
1197  D_PTR(DefaultDevice);
1198  d->pollingPeriod = msec;
1199 }
1200 
1201 uint32_t DefaultDevice::getCurrentPollingPeriod() const
1202 {
1203  D_PTR(const DefaultDevice);
1204  return d->pollingPeriod;
1205 }
1206 
1207 uint32_t &DefaultDevice::refCurrentPollingPeriod()
1208 {
1209  D_PTR(DefaultDevice);
1210  return d->pollingPeriod;
1211 }
1212 
1213 uint32_t DefaultDevice::refCurrentPollingPeriod() const
1214 {
1215  D_PTR(const DefaultDevice);
1216  return d->pollingPeriod;
1217 }
1218 
1219 void DefaultDevice::setDefaultPollingPeriod(uint32_t msec)
1220 {
1221  D_PTR(DefaultDevice);
1222  d->PollPeriodNP[0].setValue(msec);
1223  d->pollingPeriod = msec;
1224 }
1225 
1226 void DefaultDevice::setPollingPeriodRange(uint32_t minimum, uint32_t maximum)
1227 {
1228  D_PTR(DefaultDevice);
1229 
1230  d->PollPeriodNP[0].setMinMax(minimum, maximum);
1231  d->PollPeriodNP.updateMinMax();
1232 }
1233 
1234 void DefaultDevice::setActiveConnection(Connection::Interface *existingConnection)
1235 {
1236  D_PTR(DefaultDevice);
1237 
1238  if (existingConnection == d->activeConnection)
1239  return;
1240 
1241  for (Connection::Interface *oneConnection : d->connections)
1242  {
1243  if (oneConnection == d->activeConnection)
1244  {
1245  oneConnection->Deactivated();
1246  break;
1247  }
1248  }
1249 
1250  d->activeConnection = existingConnection;
1251  if (!d->ConnectionModeSP.isEmpty())
1252  {
1253  auto it = std::find(d->connections.begin(), d->connections.end(), d->activeConnection);
1254  if (it != d->connections.end())
1255  {
1256  int index = std::distance(d->connections.begin(), it);
1257  if (index >= 0)
1258  {
1259  d->ConnectionModeSP.reset();
1260  d->ConnectionModeSP[index].setState(ISS_ON);
1261  d->ConnectionModeSP.setState(IPS_OK);
1262  // If property is registerned then send back response to client
1263  INDI::Property connectionProperty = getProperty(d->ConnectionModeSP.getName(), INDI_SWITCH);
1264  if (connectionProperty && connectionProperty.getRegistered())
1265  d->ConnectionModeSP.apply();
1266  }
1267  }
1268  }
1269 }
1270 
1271 const char *DefaultDevice::getDriverExec()
1272 {
1273  return me;
1274 }
1275 
1276 const char *DefaultDevice::getDriverName()
1277 {
1278  return getDefaultName();
1279 }
1280 
1281 void DefaultDevice::setVersion(uint16_t vMajor, uint16_t vMinor)
1282 {
1283  D_PTR(DefaultDevice);
1284  d->majorVersion = vMajor;
1285  d->minorVersion = vMinor;
1286 }
1287 
1288 uint16_t DefaultDevice::getMajorVersion() const
1289 {
1290  D_PTR(const DefaultDevice);
1291  return d->majorVersion;
1292 }
1293 
1294 uint16_t DefaultDevice::getMinorVersion() const
1295 {
1296  D_PTR(const DefaultDevice);
1297  return d->minorVersion;
1298 }
1299 
1300 void DefaultDevice::setDynamicPropertiesBehavior(bool defineEnabled, bool deleteEnabled)
1301 {
1302  D_PTR(DefaultDevice);
1303  d->defineDynamicProperties = defineEnabled;
1304  d->deleteDynamicProperties = deleteEnabled;
1305 }
1306 
1307 Connection::Interface *DefaultDevice::getActiveConnection()
1308 {
1309  D_PTR(DefaultDevice);
1310  return d->activeConnection;
1311 }
1312 
1313 uint32_t DefaultDevice::getPollingPeriod() const
1314 {
1315  D_PTR(const DefaultDevice);
1316  return static_cast<uint32_t>(d->PollPeriodNP[0].getValue());
1317 }
1318 
1319 bool DefaultDevice::isConfigLoading() const
1320 {
1321  D_PTR(const DefaultDevice);
1322  return d->isConfigLoading;
1323 }
1324 
1325 bool DefaultDevice::isInitializationComplete() const
1326 {
1327  D_PTR(const DefaultDevice);
1328  return d->isInit;
1329 }
1330 
1331 }
The Interface class is the base class for all INDI connection plugins.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
virtual std::string name()=0
virtual void Deactivated()=0
Deactivated Function called by the framework when the plugin is deactivated. It is usually used to de...
virtual std::string label()=0
Class to provide basic INDI device functionality.
Definition: basedevice.h:52
INDI::PropertyNumber getNumber(const char *name) const
Definition: basedevice.cpp:89
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
void setDeviceName(const char *dev)
Set the device name.
Definition: basedevice.cpp:815
void registerProperty(const INDI::Property &property)
Register the property to be able to observe and update.
Definition: basedevice.cpp:924
INDI::PropertyText getText(const char *name) const
Definition: basedevice.cpp:94
Properties getProperties()
Return a list of all properties in the device.
Definition: basedevice.cpp:158
static std::list< DefaultDevicePrivate * > devices
static std::recursive_mutex devicesLock
DefaultDevicePrivate(DefaultDevice *defaultDevice)
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
void addPollPeriodControl()
Add Polling period control to the driver.
virtual bool purgeConfig()
purgeConfig Remove config file from disk.
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
void setSimulation(bool enable)
Toggle driver simulation status A driver can run in simulation mode if Simulation option is enabled b...
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
virtual const char * getDefaultName()=0
void addConfigurationControl()
Add Configuration control to the driver.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void addSimulationControl()
Add Simulation control to the driver.
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
void watchDevice(const char *deviceName, const std::function< void(INDI::BaseDevice)> &callback)
Add a device to the watch list.
uint32_t getPollingPeriod() const
getPollingPeriod Return the polling period.
virtual void simulationTriggered(bool enable)
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual void TimerHit()
Callback function to be called once SetTimer duration elapses.
void setDebug(bool enable)
Toggle driver debug status A driver can be more verbose if Debug option is enabled by the client.
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
bool isSimulation() const
void syncDriverInfo()
syncDriverInfo sends the current driver information to the client.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool saveAllConfigItems(FILE *fp)
saveAllConfigItems Save all the drivers' properties in the configuration file
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Process the client newBLOB command.
virtual bool loadDefaultConfig()
Load the default configuration file.
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....
void resetProperties()
Set all properties to IDLE state.
virtual void debugTriggered(bool enable)
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
void RemoveTimer(int id)
Remove timer added with SetTimer.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
uint16_t getDriverInterface() const
void addDebugControl()
Add Debug control to the driver.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
The class is used to create device instances. Class copying is not allowed. When an object is destroy...
Definition: parentdevice.h:18
Provides generic container for INDI properties.
Definition: indiproperty.h:48
const char * getName() const
bool isDynamic() const
bool getRegistered() const
void(* WeakIDSetBLOBVA)(const IBLOBVectorProperty *, const char *, va_list)
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
int(* WeakIUUpdateText)(ITextVectorProperty *, char *[], char *[], int)
int(* WeakIUUpdateNumber)(INumberVectorProperty *, double[], char *[], int n)
void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update data of an existing blob vector property.
int(* WeakIUUpdateBLOB)(IBLOBVectorProperty *, int[], int[], char *[], char *[], char *[], int n)
void(* WeakIDSetLightVA)(const ILightVectorProperty *, const char *, va_list)
void(* WeakIDDefSwitchVA)(const ISwitchVectorProperty *, const char *, va_list)
void(* WeakIDDefTextVA)(const ITextVectorProperty *, const char *, va_list)
const char * FILTER_TAB
FILTER_TAB Where all the properties for filter wheels are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
void(* WeakIDSetTextVA)(const ITextVectorProperty *, const char *, va_list)
void(* WeakIDDefBLOBVA)(const IBLOBVectorProperty *, const char *, va_list)
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
const char * DATETIME_TAB
DATETIME_TAB Where all date and time setting properties are located.
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Update the value of an existing text vector property.
const char * SATELLITE_TAB
SATELLITE_TAB.
const char * COMMUNICATION_TAB
COMMUNICATION_TAB Where all the properties required to connect/disconnect from a device are located....
const char * INFO_TAB
INFO_TAB Where all the properties for general information are located.
void ISGetProperties(const char *dev)
Get Device Properties.
void(* WeakIDDefNumberVA)(const INumberVectorProperty *, const char *, va_list)
void timerfunc(void *t)
void(* WeakIDDefLightVA)(const ILightVectorProperty *, const char *, va_list)
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
int(* WeakIUUpdateSwitch)(ISwitchVectorProperty *, ISState *, char *[], int n)
const char * ALIGNMENT_TAB
ALIGNMENT_TAB Where all the properties for guiding are located.
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
void(* WeakIDSetNumberVA)(const INumberVectorProperty *, const char *, va_list)
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
void(* WeakIDSetSwitchVA)(const ISwitchVectorProperty *, const char *, va_list)
void(* WeakIUUpdateMinMax)(const INumberVectorProperty *)
const char * SITE_TAB
SITE_TAB Where all site information setting are located.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Constants and Data structure definitions for the interface to the reference INDI C API implementation...
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ ISR_ATMOST1
Definition: indiapi.h:174
Implementations for common driver routines.
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update all BLOB members in a BLOB vector property.
Definition: indidriver.c:1422
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
Definition: indidriver.c:1200
void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
Definition: indidriver.c:1113
void IDDefNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
Definition: indidriver.c:1090
void IDDelete(const char *dev, const char *name, const char *fmt,...)
Definition: indidriver.c:132
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indidriver.c:1066
void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
Definition: indidriver.c:1263
void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
Add opening or closing tag to a configuration file. A configuration file root XML element is <INDIDri...
Definition: indidriver.c:1043
void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indidriver.c:1180
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:143
int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
Loads and processes a configuration file. Once a configuration file is successful loaded,...
Definition: indidriver.c:485
void IDDefLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indidriver.c:1136
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
Definition: indidriver.c:968
void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
Definition: indidriver.c:1156
@ INDI_TEXT
Definition: indidriver.c:59
@ INDI_NUMBER
Definition: indidriver.c:57
@ INDI_SWITCH
Definition: indidriver.c:58
@ INDI_BLOB
Definition: indidriver.c:61
int IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
Copies an existing configuration file into a default configuration file. If no default configuration ...
Definition: indidriver.c:542
int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
IUGetConfigOnSwitchIndex Opens configuration file and reads single switch property to find ON switch ...
Definition: indidriver.c:711
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1296
void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
Definition: indidriver.c:1220
char * me
Definition: indidriver.c:50
FILE * IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
Open a configuration file for writing and return a configuration file FILE pointer.
Definition: indidriver.c:994
void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indidriver.c:1240
#define DEBUG_CONF(outputFile, configuration, fileVerbosityLevel, screenVerbosityLevel)
Macro to configure the logger. Example of configuration of the Logger: DEBUG_CONF("outputfile",...
Definition: indilogger.h:38
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
#define LOGF_WARN(fmt,...)
Definition: indilogger.h:81
#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 LOG_INFO(txt)
Definition: indilogger.h:74
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
#define MAXRBUF
Definition: indiserver.cpp:102
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.cpp:150
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.cpp:644
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
Definition: lilxml.cpp:698
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.cpp:600
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.cpp:844
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.cpp:653
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.cpp:555
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.cpp:167
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.cpp:159
const char * CONNECTION
Connect to and disconnect from device.
Namespace to encapsulate INDI client, drivers, and mediator classes.
const char * getDeviceName()
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:23613
Definition: json.h:4973
static bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Definition: indilogger.cpp:145
static bool initProperties(INDI::DefaultDevice *device)
Definition: indilogger.cpp:85
static bool updateProperties(bool enable)
Definition: indilogger.cpp:113
static bool saveConfigItems(FILE *fp)
Definition: indilogger.cpp:136
static std::string getLogFile()
Definition: indilogger.h:225
bool contains(const std::string &key, const ISState &state) const
Provides decorator for Low-Level IXXXVectorProperty/IXXX.
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:471
Light vector property descriptor.
Definition: indiapi.h:417
Number vector property descriptor.
Definition: indiapi.h:319
Switch vector property descriptor.
Definition: indiapi.h:367
Text vector property descriptor.
Definition: indiapi.h:246