API
xt1121Ctrl.hpp
Go to the documentation of this file.
1 /** \file xt1121Ctrl.hpp
2  * \brief The MagAO-X Acromag XT 1121digital I/O controller.
3  *
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  * \ingroup xt1121Ctrl_files
7  */
8 
9 #ifndef xt1121Ctrl_hpp
10 #define xt1121Ctrl_hpp
11 
12 
13 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14 #include "../../magaox_git_version.h"
15 
16 #include "xtChannels.hpp"
17 
18 namespace MagAOX
19 {
20 namespace app
21 {
22 
23 
24 /** \defgroup xt1121Ctrl Acromag xt1121Controller
25  * \brief Control of an Acromag xt1121digital I/O module
26  *
27  * <a href="../handbook/operating/software/apps/xt1121Ctrl.html">Application Documentation</a>
28  *
29  * \ingroup apps
30  *
31  */
32 
33 /** \defgroup xt1121Ctrl_files Acromag xt1121Controller Files
34  * \ingroup xt1121Ctrl
35  */
36 
37 /** MagAO-X application to control an Acromag xt1121digital i/o module
38  *
39  * \ingroup xt1121Ctrl
40  *
41  */
42 class xt1121Ctrl : public MagAOXApp<>, public xt1121Channels
43 {
44 
45 protected:
46 
47  /** \name configurable parameters
48  *@{
49  */
50 
51  std::string m_address; ///< The I.P. address of the device
52 
53  uint16_t m_port {502}; ///< The port to use. Default is 502 for modbus.
54 
55  unsigned long m_powerOnWait {2}; ///< Time in sec to wait for device to boot after power on.
56 
57  ///@}
58 
59  int m_powerOnCounter {0}; ///< Counts numer of loops after power on, implements delay for camera bootup.
60 
61  modbus * m_mb {nullptr}; ///< The modbus protocol communication object
62 
63 public:
64 
65  ///Default c'tor
66  xt1121Ctrl();
67 
68  ///Destructor
69  ~xt1121Ctrl() noexcept;
70 
71  /// Setup the configuration system (called by MagAOXApp::setup())
72  virtual void setupConfig();
73 
74  /// load the configuration system results (called by MagAOXApp::setup())
75  virtual void loadConfig();
76 
77  /// Startup functions
78  /** Sets up the INDI vars.
79  *
80  */
81  virtual int appStartup();
82 
83  /// Implementation of the FSM for the Siglent SDG
84  virtual int appLogic();
85 
86  /// Implementation of the on-power-off FSM logic
87  virtual int onPowerOff();
88 
89  /// Implementation of the while-powered-off FSM
90  virtual int whilePowerOff();
91 
92  /// Do any needed shutdown tasks. Currently nothing in this app.
93  virtual int appShutdown();
94 
95  /// Get the current state of the outlets.
96  /**
97  * \returns 0 on success
98  * \returns -1 on error
99  */
100  int getState();
101 
102  //INDI:
103 protected:
104  //declare our properties
105  pcf::IndiProperty m_indiP_ch00;
106  pcf::IndiProperty m_indiP_ch01;
107  pcf::IndiProperty m_indiP_ch02;
108  pcf::IndiProperty m_indiP_ch03;
109  pcf::IndiProperty m_indiP_ch04;
110  pcf::IndiProperty m_indiP_ch05;
111  pcf::IndiProperty m_indiP_ch06;
112  pcf::IndiProperty m_indiP_ch07;
113  pcf::IndiProperty m_indiP_ch08;
114  pcf::IndiProperty m_indiP_ch09;
115  pcf::IndiProperty m_indiP_ch10;
116  pcf::IndiProperty m_indiP_ch11;
117  pcf::IndiProperty m_indiP_ch12;
118  pcf::IndiProperty m_indiP_ch13;
119  pcf::IndiProperty m_indiP_ch14;
120  pcf::IndiProperty m_indiP_ch15;
121 
122 public:
123 
124  /// Callback worker to actually set or clear a channel and send it to the device
125  /** Contains the target/current logic, and calls the xtChannels::setRegisters
126  * function, and then the modbus write_registers.
127  *
128  * \returns 0 on success
129  * \returns -1 on error
130  */
131  int channelSetCallback( size_t chNo, ///< [in] The channel number to set
132  pcf::IndiProperty & ipToSet, ///< [in] The corresponding local INDI property
133  const pcf::IndiProperty & ipRecv ///< [in] The received INDI property
134  );
135 
152 };
153 
154 inline
155 xt1121Ctrl::xt1121Ctrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
156 {
157  m_powerMgtEnabled = true;
158 
159  return;
160 }
161 
162 inline
164 {
165  if(m_mb)
166  {
167  delete m_mb;
168  };
169 
170  return;
171 }
172 
173 inline
175 {
176  config.add("device.address", "", "device.address", argType::Required, "device", "address", true, "string", "The device I.P. address.");
177  config.add("device.port", "", "device.port", argType::Required, "device", "port", true, "int", "The device port. Default is 502.");
178  config.add("device.powerOnWait", "", "device.powerOnWait", argType::Required, "device", "powerOnWait", false, "int", "Time after power-on to begin attempting connections [sec]. Default is 2 sec.");
179  config.add("device.inputOnly", "", "device.inputOnly", argType::Required, "device", "inputOnly", false, "vector<int>", "List of channels which are input-only.");
180 
181 }
182 
183 
184 ///\todo mxlib loadConfig needs to return int to propagate errors!
185 
186 inline
188 {
189  config(m_address, "device.address");
190  config(m_port, "device.port");
191  config(m_powerOnWait, "device.powerOnWait");
192 
193  std::vector<int> ino;
194  config(ino, "device.inputOnly");
195 
196  for(size_t i=0; i< ino.size();++i)
197  {
198  if(setInputOnly(ino[i]) != 0)
199  {
200  log<text_log>("Error setting channel " + std::to_string(i) + " to input only.", logPrio::LOG_ERROR);
201  }
202  }
203 }
204 
205 
206 
207 inline
209 {
210  // set up the INDI properties
211  REG_INDI_NEWPROP(m_indiP_ch00, "ch00", pcf::IndiProperty::Number);
212  m_indiP_ch00.add (pcf::IndiElement("current"));
213  m_indiP_ch00["current"].set(-1);
214  m_indiP_ch00.add (pcf::IndiElement("target"));
215 
216  REG_INDI_NEWPROP(m_indiP_ch01, "ch01", pcf::IndiProperty::Number);
217  m_indiP_ch01.add (pcf::IndiElement("current"));
218  m_indiP_ch01["current"].set(-1);
219  m_indiP_ch01.add (pcf::IndiElement("target"));
220 
221  REG_INDI_NEWPROP(m_indiP_ch02, "ch02", pcf::IndiProperty::Number);
222  m_indiP_ch02.add (pcf::IndiElement("current"));
223  m_indiP_ch02["current"].set(-1);
224  m_indiP_ch02.add (pcf::IndiElement("target"));
225 
226  REG_INDI_NEWPROP(m_indiP_ch03, "ch03", pcf::IndiProperty::Number);
227  m_indiP_ch03.add (pcf::IndiElement("current"));
228  m_indiP_ch03["current"].set(-1);
229  m_indiP_ch03.add (pcf::IndiElement("target"));
230 
231  REG_INDI_NEWPROP(m_indiP_ch04, "ch04", pcf::IndiProperty::Number);
232  m_indiP_ch04.add (pcf::IndiElement("current"));
233  m_indiP_ch04["current"].set(-1);
234  m_indiP_ch04.add (pcf::IndiElement("target"));
235 
236  REG_INDI_NEWPROP(m_indiP_ch05, "ch05", pcf::IndiProperty::Number);
237  m_indiP_ch05.add (pcf::IndiElement("current"));
238  m_indiP_ch05["current"].set(-1);
239  m_indiP_ch05.add (pcf::IndiElement("target"));
240 
241  REG_INDI_NEWPROP(m_indiP_ch06, "ch06", pcf::IndiProperty::Number);
242  m_indiP_ch06.add (pcf::IndiElement("current"));
243  m_indiP_ch06["current"].set(-1);
244  m_indiP_ch06.add (pcf::IndiElement("target"));
245 
246  REG_INDI_NEWPROP(m_indiP_ch07, "ch07", pcf::IndiProperty::Number);
247  m_indiP_ch07.add (pcf::IndiElement("current"));
248  m_indiP_ch07["current"].set(-1);
249  m_indiP_ch07.add (pcf::IndiElement("target"));
250 
251  REG_INDI_NEWPROP(m_indiP_ch08, "ch08", pcf::IndiProperty::Number);
252  m_indiP_ch08.add (pcf::IndiElement("current"));
253  m_indiP_ch08["current"].set(-1);
254  m_indiP_ch08.add (pcf::IndiElement("target"));
255 
256  REG_INDI_NEWPROP(m_indiP_ch09, "ch09", pcf::IndiProperty::Number);
257  m_indiP_ch09.add (pcf::IndiElement("current"));
258  m_indiP_ch09["current"].set(-1);
259  m_indiP_ch09.add (pcf::IndiElement("target"));
260 
261  REG_INDI_NEWPROP(m_indiP_ch10, "ch10", pcf::IndiProperty::Number);
262  m_indiP_ch10.add (pcf::IndiElement("current"));
263  m_indiP_ch10["current"].set(-1);
264  m_indiP_ch10.add (pcf::IndiElement("target"));
265 
266  REG_INDI_NEWPROP(m_indiP_ch11, "ch11", pcf::IndiProperty::Number);
267  m_indiP_ch11.add (pcf::IndiElement("current"));
268  m_indiP_ch11["current"].set(-1);
269  m_indiP_ch11.add (pcf::IndiElement("target"));
270 
271  REG_INDI_NEWPROP(m_indiP_ch12, "ch12", pcf::IndiProperty::Number);
272  m_indiP_ch12.add (pcf::IndiElement("current"));
273  m_indiP_ch12["current"].set(-1);
274  m_indiP_ch12.add (pcf::IndiElement("target"));
275 
276  REG_INDI_NEWPROP(m_indiP_ch13, "ch13", pcf::IndiProperty::Number);
277  m_indiP_ch13.add (pcf::IndiElement("current"));
278  m_indiP_ch13["current"].set(-1);
279  m_indiP_ch13.add (pcf::IndiElement("target"));
280 
281  REG_INDI_NEWPROP(m_indiP_ch14, "ch14", pcf::IndiProperty::Number);
282  m_indiP_ch14.add (pcf::IndiElement("current"));
283  m_indiP_ch14["current"].set(-1);
284  m_indiP_ch14.add (pcf::IndiElement("target"));
285 
286  REG_INDI_NEWPROP(m_indiP_ch15, "ch15", pcf::IndiProperty::Number);
287  m_indiP_ch15.add (pcf::IndiElement("current"));
288  m_indiP_ch15["current"].set(-1);
289  m_indiP_ch15.add (pcf::IndiElement("target"));
290 
291 
292  return 0;
293 
294 }
295 
296 
297 
298 inline
300 {
301  if( state() == stateCodes::POWERON )
302  {
303  if(m_powerOnCounter*m_loopPause > ((double) m_powerOnWait)*1e9)
304  {
306  m_powerOnCounter = 0;
307  }
308  else
309  {
311  return 0;
312  }
313  }
314 
316  {
317  std::string response;
318 
319  //Might have gotten here because of a power off.
320  if(m_powerState == 0) return 0;
321 
322  m_mb = new(std::nothrow) modbus(m_address, m_port);
323 
324  if(m_mb == nullptr)
325  {
326  return log<software_critical, -1>({__FILE__, __LINE__, "allocation failure"});
327  }
328 
330 
331  if( m_mb->modbus_connect() == false)
332  {
333  if(!stateLogged())
334  {
335  log<text_log>("connect failed at " + m_address + ":" + std::to_string(m_port));
336  }
337  delete m_mb;
338  m_mb = nullptr;
339  return 0;
340  }
341 
343  log<text_log>("connected to " + m_address + ":" + std::to_string(m_port));
344  }
345 
346  if( state() == stateCodes::CONNECTED )
347  {
348  //Get a lock
349  std::unique_lock<std::mutex> lock(m_indiMutex);
350 
351  if( getState() == 0 )
352  {
354  return 0;
355  }
356  else
357  {
359  return log<software_error,0>({__FILE__,__LINE__});
360  }
361  }
362 
364  {
365  //Get a lock if we can
366  std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
367 
368  //but don't wait for it, just go back around.
369  if(!lock.owns_lock()) return 0;
370 
371  if(getState() < 0)
372  {
373  if(m_powerState == 0) return 0;
374 
376  return 0;
377  }
378 
379  return 0;
380  }
381 
382  //Fall through check?
383 
384  return 0;
385 
386 }
387 
388 inline
390 {
391  m_powerOnCounter = 0;
392 
393  std::lock_guard<std::mutex> lock(m_indiMutex);
394 
395  updateIfChanged(m_indiP_ch00, "current", -1);
396  updateIfChanged(m_indiP_ch00, "target", -1);
397 
398  updateIfChanged(m_indiP_ch01, "current", -1);
399  updateIfChanged(m_indiP_ch01, "target", -1);
400 
401  updateIfChanged(m_indiP_ch02, "current", -1);
402  updateIfChanged(m_indiP_ch02, "target", -1);
403 
404  updateIfChanged(m_indiP_ch03, "current", -1);
405  updateIfChanged(m_indiP_ch03, "target", -1);
406 
407  updateIfChanged(m_indiP_ch04, "current", -1);
408  updateIfChanged(m_indiP_ch04, "target", -1);
409 
410  updateIfChanged(m_indiP_ch05, "current", -1);
411  updateIfChanged(m_indiP_ch05, "target", -1);
412 
413  updateIfChanged(m_indiP_ch06, "current", -1);
414  updateIfChanged(m_indiP_ch06, "target", -1);
415 
416  updateIfChanged(m_indiP_ch07, "current", -1);
417  updateIfChanged(m_indiP_ch07, "target", -1);
418 
419  updateIfChanged(m_indiP_ch08, "current", -1);
420  updateIfChanged(m_indiP_ch08, "target", -1);
421 
422  updateIfChanged(m_indiP_ch09, "current", -1);
423  updateIfChanged(m_indiP_ch09, "target", -1);
424 
425  updateIfChanged(m_indiP_ch10, "current", -1);
426  updateIfChanged(m_indiP_ch10, "target", -1);
427 
428  updateIfChanged(m_indiP_ch11, "current", -1);
429  updateIfChanged(m_indiP_ch11, "target", -1);
430 
431  updateIfChanged(m_indiP_ch12, "current", -1);
432  updateIfChanged(m_indiP_ch12, "target", -1);
433 
434  updateIfChanged(m_indiP_ch13, "current", -1);
435  updateIfChanged(m_indiP_ch13, "target", -1);
436 
437  updateIfChanged(m_indiP_ch14, "current", -1);
438  updateIfChanged(m_indiP_ch14, "target", -1);
439 
440  updateIfChanged(m_indiP_ch15, "current", -1);
441  updateIfChanged(m_indiP_ch15, "target", -1);
442 
443 
444  return 0;
445 }
446 
447 inline
449 {
450  return 0;
451 }
452 
453 inline
455 {
456  if(m_mb) m_mb->modbus_close();
457  return 0;
458 }
459 
460 
461 
462 inline
464 {
465  uint16_t input_regs[numRegisters];
466 
467  try
468  {
469  ///\todo this hangs if power goes off during call
471  }
472  catch(std::exception & e)
473  {
474  if(m_powerState == 0) return 0; //due to power off
475 
476  return log<software_error,-1>({__FILE__, __LINE__, std::string("Exception caught: ") + e.what()});
477  }
478 
479  if( readRegisters(input_regs) !=0 )
480  {
481  return log<software_error,-1>({__FILE__, __LINE__});
482  }
483 
484  updateIfChanged(m_indiP_ch00, "current", channel(0));
485  updateIfChanged(m_indiP_ch01, "current", channel(1));
486  updateIfChanged(m_indiP_ch02, "current", channel(2));
487  updateIfChanged(m_indiP_ch03, "current", channel(3));
488  updateIfChanged(m_indiP_ch04, "current", channel(4));
489  updateIfChanged(m_indiP_ch05, "current", channel(5));
490  updateIfChanged(m_indiP_ch06, "current", channel(6));
491  updateIfChanged(m_indiP_ch07, "current", channel(7));
492  updateIfChanged(m_indiP_ch08, "current", channel(8));
493  updateIfChanged(m_indiP_ch09, "current", channel(9));
494  updateIfChanged(m_indiP_ch10, "current", channel(10));
495  updateIfChanged(m_indiP_ch11, "current", channel(11));
496  updateIfChanged(m_indiP_ch12, "current", channel(12));
497  updateIfChanged(m_indiP_ch13, "current", channel(13));
498  updateIfChanged(m_indiP_ch14, "current", channel(14));
499  updateIfChanged(m_indiP_ch15, "current", channel(15));
500 
501  return 0;
502 
503 
504 }
505 
506 
508  pcf::IndiProperty & ipToSet,
509  const pcf::IndiProperty & ipRecv
510  )
511 {
512  int current = -1, target = -1;
513 
514  if(ipRecv.find("current"))
515  {
516  current = ipRecv["current"].get<unsigned>();
517  }
518 
519  if(ipRecv.find("target"))
520  {
521  target = ipRecv["target"].get<unsigned>();
522  }
523 
524  if(target == -1) target = current;
525 
526  if(target < 0) return 0;
527 
528  //Lock the mutex, waiting if necessary
529  std::unique_lock<std::mutex> lock(m_indiMutex);
530 
531  if(target == 0) clearChannel(chNo);
532  else setChannel(chNo);
533 
534  target = channel(chNo); //This checks for inputOnly
535 
536  updateIfChanged(ipToSet, "target", target);
537 
538  uint16_t input_regs[numRegisters];
539 
540  if( setRegisters(input_regs) !=0 )
541  {
542  return log<software_error,-1>({__FILE__, __LINE__});
543  }
544 
545  try
546  {
548  }
549  catch(std::exception & e)
550  {
551  if(m_powerState == 0) return 0; //due to power off
552 
553  return log<software_error,-1>({__FILE__, __LINE__, std::string("Exception caught: ") + e.what()});
554  }
555 
556 
557  log<text_log>("Set channel " + std::to_string(chNo) + " to " + std::to_string(target));
558 
559  return 0;
560 
561 }
562 
564 {
566 
568 
569  return -1;
570 }
571 
573 {
575 
577 
578  return -1;
579 }
580 
582 {
584 
586 
587  return -1;
588 }
589 
591 {
593 
595 
596  return -1;
597 }
598 
600 {
602 
604 
605  return -1;
606 }
607 
609 {
611 
613 
614  return -1;
615 }
616 
618 {
620 
622 
623  return -1;
624 }
625 
627 {
629 
631 
632  return -1;
633 }
634 
636 {
638 
640 
641  return -1;
642 }
643 
645 {
647 
649 
650  return -1;
651 }
652 
654 {
656 
658 
659  return -1;
660 }
661 
663 {
665 
667 
668  return -1;
669 }
670 
672 {
674 
676 
677  return -1;
678 }
679 
681 {
683 
685 
686  return -1;
687 }
688 
690 {
692 
694 
695  return -1;
696 }
697 
699 {
701 
703 
704  return -1;
705 }
706 
707 
708 }//namespace app
709 } //namespace MagAOX
710 #endif
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
Definition: MagAOXApp.hpp:2877
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
unsigned long m_loopPause
The time in nanoseconds to pause the main loop. The appLogic() function of the derived class is calle...
Definition: MagAOXApp.hpp:100
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
Definition: MagAOXApp.hpp:995
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
Definition: MagAOXApp.hpp:2140
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1590
std::mutex m_indiMutex
Mutex for locking INDI communications.
Definition: MagAOXApp.hpp:540
bool m_powerMgtEnabled
Flag controls whether power mgt is used. Set this in the constructor of a derived app....
Definition: MagAOXApp.hpp:981
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
Definition: xt1121Ctrl.hpp:174
pcf::IndiProperty m_indiP_ch11
Definition: xt1121Ctrl.hpp:116
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
Definition: xt1121Ctrl.hpp:187
virtual int appLogic()
Implementation of the FSM for the Siglent SDG.
Definition: xt1121Ctrl.hpp:299
pcf::IndiProperty m_indiP_ch02
Definition: xt1121Ctrl.hpp:107
pcf::IndiProperty m_indiP_ch14
Definition: xt1121Ctrl.hpp:119
virtual int appStartup()
Startup functions.
Definition: xt1121Ctrl.hpp:208
~xt1121Ctrl() noexcept
Destructor.
Definition: xt1121Ctrl.hpp:163
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
Definition: xt1121Ctrl.hpp:454
pcf::IndiProperty m_indiP_ch07
Definition: xt1121Ctrl.hpp:112
std::string m_address
The I.P. address of the device.
Definition: xt1121Ctrl.hpp:51
uint16_t m_port
The port to use. Default is 502 for modbus.
Definition: xt1121Ctrl.hpp:53
pcf::IndiProperty m_indiP_ch10
Definition: xt1121Ctrl.hpp:115
int getState()
Get the current state of the outlets.
Definition: xt1121Ctrl.hpp:463
pcf::IndiProperty m_indiP_ch00
Definition: xt1121Ctrl.hpp:105
pcf::IndiProperty m_indiP_ch08
Definition: xt1121Ctrl.hpp:113
pcf::IndiProperty m_indiP_ch06
Definition: xt1121Ctrl.hpp:111
pcf::IndiProperty m_indiP_ch15
Definition: xt1121Ctrl.hpp:120
int m_powerOnCounter
Counts numer of loops after power on, implements delay for camera bootup.
Definition: xt1121Ctrl.hpp:59
pcf::IndiProperty m_indiP_ch01
Definition: xt1121Ctrl.hpp:106
pcf::IndiProperty m_indiP_ch05
Definition: xt1121Ctrl.hpp:110
xt1121Ctrl()
Default c'tor.
Definition: xt1121Ctrl.hpp:155
pcf::IndiProperty m_indiP_ch09
Definition: xt1121Ctrl.hpp:114
virtual int whilePowerOff()
Implementation of the while-powered-off FSM.
Definition: xt1121Ctrl.hpp:448
modbus * m_mb
The modbus protocol communication object.
Definition: xt1121Ctrl.hpp:61
virtual int onPowerOff()
Implementation of the on-power-off FSM logic.
Definition: xt1121Ctrl.hpp:389
pcf::IndiProperty m_indiP_ch12
Definition: xt1121Ctrl.hpp:117
unsigned long m_powerOnWait
Time in sec to wait for device to boot after power on.
Definition: xt1121Ctrl.hpp:55
pcf::IndiProperty m_indiP_ch03
Definition: xt1121Ctrl.hpp:108
pcf::IndiProperty m_indiP_ch13
Definition: xt1121Ctrl.hpp:118
INDI_NEWCALLBACK_DECL(xt1121Ctrl, m_indiP_ch00)
pcf::IndiProperty m_indiP_ch04
Definition: xt1121Ctrl.hpp:109
int channelSetCallback(size_t chNo, pcf::IndiProperty &ipToSet, const pcf::IndiProperty &ipRecv)
Callback worker to actually set or clear a channel and send it to the device.
Definition: xt1121Ctrl.hpp:507
Modbus Operator Class.
Definition: modbus.hpp:63
bool modbus_connect()
Definition: modbus.cpp:19
void modbus_read_input_registers(int address, int amount, uint16_t *buffer)
Definition: modbus.cpp:131
void modbus_set_slave_id(int id)
Definition: modbus.cpp:15
void modbus_close()
Definition: modbus.cpp:49
void modbus_write_registers(int address, int amount, uint16_t *value)
Definition: modbus.cpp:254
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
Definition: indiMacros.hpp:229
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:50
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
Definition: stateCodes.hpp:38
@ READY
The device is ready for operation, but is not operating.
Definition: stateCodes.hpp:51
@ CONNECTED
The application has connected to the device or service.
Definition: stateCodes.hpp:45
@ NOTCONNECTED
The application is not connected to the device or service.
Definition: stateCodes.hpp:44
@ POWERON
The device power is on.
Definition: stateCodes.hpp:43
const pcf::IndiProperty & ipRecv
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
Definition: dm.hpp:24
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Definition: logPriority.hpp:40
Software CRITICAL log entry.
Software ERR log entry.
Utility class for managing Acromag xt12XX digital I/O channels.
Definition: xtChannels.hpp:23
int setRegisters(uint16_t registers[numRegisters])
Set registers based on current channel states.
Definition: xtChannels.hpp:154
int setChannel(size_t chNo)
Set a channel to true.
Definition: xtChannels.hpp:110
static constexpr int numRegisters
The number of registers needed for the number of channels.
Definition: xtChannels.hpp:26
int channel(size_t chNo)
Gets the current state of a channel.
Definition: xtChannels.hpp:193
int setInputOnly(size_t chNo)
Set a channel to be input only.
Definition: xtChannels.hpp:126
int clearChannel(size_t chNo)
Set a channel to false.
Definition: xtChannels.hpp:136
int readRegisters(uint16_t registers[numRegisters])
Read channel states from the registers.
Definition: xtChannels.hpp:178
Utility class for managing Acromag xt12XX digital I/O channels.