API
koolanceCtrl.hpp
Go to the documentation of this file.
1 /** \file koolanceCtrl.hpp
2  * \brief The MagAO-X Koolance Controller header file
3  *
4  * \ingroup koolanceCtrl_files
5  */
6 
7 #ifndef koolanceCtrl_hpp
8 #define koolanceCtrl_hpp
9 
10 
11 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12 #include "../../magaox_git_version.h"
13 
14 /** \defgroup koolanceCtrl
15  * \brief The MagAO-X application to monitor and control a Koolance cooler
16  *
17  * <a href="../handbook/operating/software/apps/koolanceCtrl.html">Application Documentation</a>
18  *
19  * \ingroup apps
20  *
21  */
22 
23 /** \defgroup koolanceCtrl_files
24  * \ingroup koolanceCtrl
25  */
26 
27 namespace MagAOX
28 {
29 namespace app
30 {
31 
32 /// The MagAO-X Koolance Controller
33 /** This application will monitor a Koolance v1 or v2 protocol controller. If v2, will also allow
34  * changing of pump and fan settings via INDI.
35  *
36  * \ingroup koolanceCtrl
37  */
38 class koolanceCtrl : public MagAOXApp<true>, public tty::usbDevice, public dev::telemeter<koolanceCtrl>
39 {
40 
41  //Give the test harness access.
42  friend class koolanceCtrl_test;
43 
44  friend class dev::telemeter<koolanceCtrl>;
45 protected:
46 
47  /** \name Configurable Parameters
48  *@{
49  */
50 
51  //here add parameters which will be config-able at runtime
52 
53  ///@}
54 
55  size_t m_protocolChars {0}; ///< Will be set to 43 if protocol 1, and set to 51 if protocol 2.
56 
57  bool m_indiSetup {false}; ///< Whether or not INDI has been set up after initial protocol determination.
58 
59  float m_liqTemp {0}; ///< The liquid temperature
60  float m_flowRate {0}; ///< The flow rate
61  int m_pumpLvl {0}; ///< The pump power level, 1-10
62  int m_pumpRPM {0}; ///< The pump RPM
63  int m_fanRPM {0}; ///< The fan RPM
64  int m_fanLvl {0}; ///< The fan power level, 0-100
65 
66 
67 
68 public:
69  /// Default c'tor.
70  koolanceCtrl();
71 
72  /// D'tor, declared and defined for noexcept.
73  ~koolanceCtrl() noexcept
74  {}
75 
76  virtual void setupConfig();
77 
78  /// Implementation of loadConfig logic, separated for testing.
79  /** This is called by loadConfig().
80  */
81  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
82 
83  virtual void loadConfig();
84 
85  /// Startup function
86  /**
87  *
88  */
89  virtual int appStartup();
90 
91  /// Implementation of the FSM for koolanceCtrl.
92  /**
93  * \returns 0 on no critical error
94  * \returns -1 on an error requiring shutdown
95  */
96  virtual int appLogic();
97 
98  /// Shutdown the app.
99  /**
100  *
101  */
102  virtual int appShutdown();
103 
104  /// Initial connection to controller
105  /** Determine protocol in use based on number of characters in response
106  * and sets up INDI appropriately.
107  *
108  * Calls to this function should be mutexed.
109  *
110  * \returns 0 on success
111  * \returns -1 on an error
112  */
113  int initialConnect();
114 
115  /// Get status from controller and updated INDI.
116  /**
117  *
118  * Calls to this function should be mutexed.
119  *
120  * \returns 0 on success
121  * \returns -1 on an error
122  */
123  int getStatus();
124 
125  /// Set the pump level
126  /**
127  * Calls to this function should be mutexed.
128  *
129  * \returns 0 on success
130  * \returns -1 on an error
131  */
132  int setPumpLvl(int lvl /**< [in] the new level */);
133 
134  /// Set the fan level
135  /**
136  * Calls to this function should be mutexed.
137  *
138  * \returns 0 on success
139  * \returns -1 on an error
140  */
141  int setFanLvl(int lvl /**< [in] the new level */);
142 
143  /** \name INDI
144  *
145  *@{
146  */
147 protected:
148  //declare our properties
149  pcf::IndiProperty m_indiP_status;
150  pcf::IndiProperty m_indiP_pumplvl;
151  pcf::IndiProperty m_indiP_fanlvl;
152 
153 public:
156 
157  ///@}
158 
159  /** \name Telemeter Interface
160  *
161  * @{
162  */
163  int checkRecordTimes();
164 
165  int recordTelem( const telem_cooler * );
166 
167  int recordCooler(bool force = false);
168 
169  ///@}
170 
171 
172 };
173 
174 koolanceCtrl::koolanceCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
175 {
176  return;
177 }
178 
180 {
182 
184 
185 }
186 
187 int koolanceCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
188 {
189  this->m_baudRate = B9600; //default for a Koolance controller. Will be overridden by any config setting.
190 
191  int rv = tty::usbDevice::loadConfig(_config);
192 
193  if(rv != 0 && rv != TTY_E_NODEVNAMES && rv != TTY_E_DEVNOTFOUND) //Ignore error if not plugged in
194  {
195  log<software_error>( {__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
196  }
197 
198  return 0;
199 }
200 
202 {
203  loadConfigImpl(config);
204 
206 }
207 
209 {
211  {
212  log<text_log>( "In appStartup but in state UNINITIALIZED.", logPrio::LOG_CRITICAL );
213  return -1;
214  }
215 
216  // set up the INDI properties
217  REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Number);
218  m_indiP_status.add(pcf::IndiElement("liquid_temp"));
219  m_indiP_status.add(pcf::IndiElement("flow_rate"));
220  m_indiP_status.add(pcf::IndiElement("pump_rpm"));
221  m_indiP_status.add(pcf::IndiElement("fan_rpm"));
222 
224  {
225  return log<software_error,-1>({__FILE__,__LINE__});
226  }
227 
229  return 0;
230 }
231 
233 {
234 
235  if( state() == stateCodes::NODEVICE )
236  {
238  if(rv < 0 && rv != TTY_E_DEVNOTFOUND && rv != TTY_E_NODEVNAMES)
239  {
241  if(!stateLogged())
242  {
243  log<software_critical>({__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
244  }
245  return -1;
246  }
247 
248  if(rv == TTY_E_DEVNOTFOUND || rv == TTY_E_NODEVNAMES)
249  {
251 
252  if(!stateLogged())
253  {
254  std::stringstream logs;
255  logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " not found in udev";
256  log<text_log>(logs.str());
257  }
258  return 0;
259  }
260  else
261  {
262  std::stringstream logs;
263  logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " found in udev as " << m_deviceName;
264  log<text_log>(logs.str());
265 
267  }
268  }
269 
271  {
272  int rv = 0;
273  {
274  elevatedPrivileges ep(this);
275  rv = connect();
276  }
277 
278  if(rv < 0)
279  {
280  int nrv = tty::usbDevice::getDeviceName();
281  if(nrv < 0 && nrv != TTY_E_DEVNOTFOUND && nrv != TTY_E_NODEVNAMES)
282  {
284  if(!stateLogged()) log<software_critical>({__FILE__, __LINE__, nrv, tty::ttyErrorString(nrv)});
285  return -1;
286  }
287 
288  if(nrv == TTY_E_DEVNOTFOUND || nrv == TTY_E_NODEVNAMES)
289  {
291 
292  if(!stateLogged())
293  {
294  std::stringstream logs;
295  logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " no longer found in udev";
296  log<text_log>(logs.str());
297  }
298  return 0;
299  }
300 
301  //if connect failed, and there is a device, then we have some other problem.
302  sleep(1); //wait to see if power state updates
303  if(m_powerState == 0) return 0;
304 
305  //Ok we can't figure this out, die.
307  if(!stateLogged()) log<software_error>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
308  return -1;
309 
310  }
311  else
312  {
313  std::unique_lock<std::mutex> lock(m_indiMutex);
314  if(initialConnect () == 0)
315  {
317  }
318  else
319  {
320  if(!stateLogged())
321  {
322  log<text_log>("no response from device");
323  }
324  return 0;
325  }
326  }
327 
329  {
330  std::stringstream logs;
331  logs << "Connected to koolance system on " << m_deviceName;
332  log<text_log>(logs.str());
334  return 0;
335  }
336 
337  }
338 
339  if( state() == stateCodes::READY )
340  {
341  { //mutex scope
342  std::unique_lock<std::mutex> lock(m_indiMutex);
343  if(getStatus() < 0)
344  {
345  log<software_error>({__FILE__,__LINE__});
346  }
347  }
348 
350  {
351  log<software_error>({__FILE__, __LINE__});
352  return 0;
353  }
354  return 0;
355  }
356 
357  return 0;
358 }
359 
361 {
363  return 0;
364 }
365 
366 
367 
369 {
370  int rv;
371 
372  std::vector<unsigned char> com;
373  com.resize(3, '\0');
374  com[0] = 0xCF;
375  com[1] = 0x01;
376  com[2] = 0x08;
377 
378  rv = write(m_fileDescrip, com.data(), com.size());
379 
380  if(rv < 0)
381  {
382  log<software_error>({__FILE__,__LINE__, errno, "error from write"});
383  ::close(m_fileDescrip);
384  m_fileDescrip = 0;
386 
387  return -1;
388  }
389 
390  std::vector<unsigned char> resp;
391  resp.resize(51);
392 
393  mx::sys::milliSleep(1000); //Sleep for a long time to make sure device responds
394  int readBytes;
395  rv = tty::ttyReadRaw(resp, readBytes, m_fileDescrip, 1000); ///\todo needs to be iodevice
396 
397  if(rv < 0)
398  {
399  log<software_error>({__FILE__,__LINE__, errno, "error from read"});
400  ::close(m_fileDescrip);
401  m_fileDescrip = 0;
403 
404  return -1;
405  }
406 
407  if(readBytes == 43)
408  {
409  log<text_log>("found protocol 1 device");
410  m_protocolChars = 43;
411  }
412  else if(readBytes == 51)
413  {
414  log<text_log>("found protocol 2 device");
415  m_protocolChars = 51;
416  }
417  else
418  {
419  return -1;
420  }
421 
422  if(!m_indiSetup)
423  {
424  if(readBytes == 43)
425  {
426  REG_INDI_NEWPROP_NOCB(m_indiP_pumplvl, "pump_level", pcf::IndiProperty::Number);
427  m_indiP_pumplvl.add(pcf::IndiElement("current"));
428 
429  REG_INDI_NEWPROP_NOCB(m_indiP_fanlvl, "fan_level", pcf::IndiProperty::Number);
430  m_indiP_fanlvl.add(pcf::IndiElement("current"));
431  }
432  else
433  {
434  createStandardIndiNumber<int>( m_indiP_pumplvl, "pump_level", 1, 10, 1, "%d", "Pump Level", "Lab");
436 
437  createStandardIndiNumber<int>( m_indiP_fanlvl, "fan_level", 0, 100, 1, "%d", "Fan Level", "Lab");
439  }
440 
441  m_indiSetup = true;
442  }
443 
444  return 0;
445 }
446 
448 {
449  int rv;
450 
451  std::vector<unsigned char> com;
452  com.resize(3, '\0');
453  com[0] = 0xCF;
454  com[1] = 0x01;
455  com[2] = 0x08;
456 
457  rv = write(m_fileDescrip, com.data(), com.size());
458 
459  if(rv < 0)
460  {
461  log<software_error>({__FILE__,__LINE__, errno, "error from write"});
462  ::close(m_fileDescrip);
463  m_fileDescrip = 0;
465 
466  return -1;
467  }
468 
469  std::string resp;
470 
471  rv = tty::ttyRead(resp, m_protocolChars, m_fileDescrip, 1000); ///\todo needs to be iodevice
472 
473  if(rv < 0)
474  {
475  log<software_error>({__FILE__,__LINE__, errno, "error from read"});
476  ::close(m_fileDescrip);
477  m_fileDescrip = 0;
479 
480  return -1;
481  }
482 
483  if(resp.size() == m_protocolChars)
484  {
485  m_liqTemp = ((float) (( (unsigned char)resp[2] << 8) + (unsigned char)resp[3]-2000)) / 10.0;
486  m_flowRate = ( (float) ((unsigned char)resp[12] << 8) + (unsigned char)resp[13]) / 10.0;
487  m_fanRPM = ((unsigned char)resp[8] << 8) + (unsigned char)resp[9];
488  m_pumpRPM = ((unsigned char)resp[10] << 8) + (unsigned char)resp[11];
489  m_fanLvl = (unsigned char)resp[15];
490  m_pumpLvl = (unsigned char)resp[17];
491 
492  recordCooler();
493 // std::cout << std::dec;
494 // std::cout << "liq. temp: " << m_liqTemp << " C\n";
495 // std::cout << "flow rate: " << m_flowRate << " LPM\n";
496 // std::cout << "pump lvl: " << m_pumpLvl << "\n";
497 // std::cout << "pump speed:" << m_pumpRPM << " RPM\n";
498 // std::cout << "fan lvl: " << m_fanLvl << "\n";
499 // std::cout << "fan speed:" << m_fanRPM << " RPM\n";
500 
501  updateIfChanged(m_indiP_status, "liquid_temp", m_liqTemp);
507 
508  return 0;
509  }
510  else
511  {
512  log<software_error>({__FILE__,__LINE__, std::string("wrong response size (") + std::to_string(resp.size()) + ") returned"});
513  ::close(m_fileDescrip);
514  m_fileDescrip = 0;
516 
517  return -1;
518  }
519 }
520 
522 {
523  if(m_protocolChars == 43) return 0;
524 
525  int rv;
526 
527  std::vector<unsigned char> com;
528  com.resize(m_protocolChars, '\0');
529  com[0] = 0xCF;
530  com[1] = 0x04;
531 
532  com[15] = m_fanLvl;
533  com[17] = lvl;
534 
535  //Disable most stuff.
536  for(size_t n = 20; n <m_protocolChars-1; ++n) com[n] = 0xAA;
537 
538  //Preserve units
539  if(m_protocolChars > 43)
540  {
541  com[44] = 0;
542  com[45] = 0x0001;
543  com[46] = 0;
544  com[47] = 0;
545  com[48] = 0;
546  com[49] = 0;
547  }
548 
549  int checksum = 0;
550  for(size_t n = 0; n <m_protocolChars-1; ++n) checksum += com[n];
551  com[m_protocolChars-1] = checksum % 0x64;
552 
553  rv = write(m_fileDescrip, com.data(), com.size());
554 
555  if(rv < 0)
556  {
557  log<software_error>({__FILE__,__LINE__, errno, "error from write"});
558  ::close(m_fileDescrip);
559  m_fileDescrip = 0;
561 
562  return -1;
563  }
564 
565  log<text_log>("set pump level to " + std::to_string(lvl));
566 
567  return 0;
568 }
569 
571 {
572  if(m_protocolChars == 43) return 0;
573 
574  int rv;
575 
576  std::vector<unsigned char> com;
577  com.resize(m_protocolChars, '\0');
578  com[0] = 0xCF;
579  com[1] = 0x04;
580 
581  com[15] = lvl;
582  com[17] = m_pumpLvl;
583 
584  //Disable most stuff.
585  for(size_t n = 20; n <m_protocolChars-1; ++n) com[n] = 0xAA;
586 
587  //Preserve units
588  if(m_protocolChars > 43)
589  {
590  com[44] = 0;
591  com[45] = 0x0001;
592  com[46] = 0;
593  com[47] = 0;
594  com[48] = 0;
595  com[49] = 0;
596  }
597 
598  int checksum = 0;
599  for(size_t n = 0; n <m_protocolChars-1; ++n) checksum += com[n];
600  com[m_protocolChars-1] = checksum % 0x64;
601 
602  rv = write(m_fileDescrip, com.data(), com.size());
603 
604  if(rv < 0)
605  {
606  log<software_error>({__FILE__,__LINE__, errno, "error from write"});
607  ::close(m_fileDescrip);
608  m_fileDescrip = 0;
610 
611  return -1;
612  }
613 
614  log<text_log>("set fan level to " + std::to_string(lvl));
615 
616  return 0;
617 }
618 
619 INDI_NEWCALLBACK_DEFN(koolanceCtrl, m_indiP_pumplvl)(const pcf::IndiProperty &ipRecv)
620 {
621  if(ipRecv.getName() != m_indiP_pumplvl.getName())
622  {
623  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
624  return -1;
625  }
626 
627  int lvl = -1;
628 
629  if( ipRecv.find("current") )
630  {
631  lvl = ipRecv["current"].get<int>();
632  }
633 
634  if( ipRecv.find("target") )
635  {
636  lvl = ipRecv["target"].get<int>();
637  }
638 
639  if(lvl < 1 || lvl > 10)
640  {
641  log<software_error>({__FILE__,__LINE__, "Pump level out of range"});
642  return 0;
643  }
644 
645  std::unique_lock<std::mutex> lock(m_indiMutex);
646  updateIfChanged(m_indiP_pumplvl, "target", lvl);
647  return setPumpLvl(lvl);
648 
649 
650 }
651 
652 INDI_NEWCALLBACK_DEFN(koolanceCtrl, m_indiP_fanlvl)(const pcf::IndiProperty &ipRecv)
653 {
654  if(ipRecv.getName() != m_indiP_fanlvl.getName())
655  {
656  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
657  return -1;
658  }
659 
660 
661  int lvl = -1;
662 
663  if( ipRecv.find("current") )
664  {
665  lvl = ipRecv["current"].get<int>();
666  }
667 
668  if( ipRecv.find("target") )
669  {
670  lvl = ipRecv["target"].get<int>();
671  }
672 
673  if(lvl < 0 || lvl > 100)
674  {
675  log<software_error>({__FILE__,__LINE__, "Fan level out of range"});
676  return 0;
677  }
678 
679  std::unique_lock<std::mutex> lock(m_indiMutex);
680  updateIfChanged(m_indiP_fanlvl, "target", lvl);
681  return setFanLvl(lvl);
682 
683  return 0;
684 }
685 
686 inline
688 {
690 }
691 
692 inline
694 {
695  return recordCooler(true);
696 }
697 
698 inline
699 int koolanceCtrl::recordCooler( bool force )
700 {
701  static float last_liqTemp = std::numeric_limits<float>::max();
702  static float last_flowRate = std::numeric_limits<float>::max();
703  static int last_pumpLvl = std::numeric_limits<int>::max();
704  static int last_pumpRPM = std::numeric_limits<int>::max();
705  static int last_fanRPM = std::numeric_limits<int>::max();
706  static int last_fanLvl = std::numeric_limits<int>::max();
707 
708  if( m_liqTemp != last_liqTemp || m_flowRate != last_flowRate || m_pumpLvl != last_pumpLvl ||
709  m_pumpRPM != last_pumpRPM || m_fanRPM != last_fanRPM || m_fanLvl != last_fanLvl || force )
710  {
711  telem<telem_cooler>({m_liqTemp, m_flowRate, (uint8_t) m_pumpLvl, (uint16_t) m_pumpRPM, (uint8_t) m_fanLvl, (uint16_t) m_fanRPM});
712 
713  last_liqTemp = m_liqTemp;
714  last_flowRate = m_flowRate;
715  last_pumpLvl = m_pumpLvl;
716  last_pumpRPM = m_pumpRPM;
717  last_fanLvl = m_fanLvl;
718  last_fanRPM = m_fanRPM;
719  }
720 
721  return 0;
722 }
723 
724 } //namespace app
725 } //namespace MagAOX
726 
727 #endif //koolanceCtrl_hpp
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
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
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
The MagAO-X Koolance Controller.
float m_liqTemp
The liquid temperature.
size_t m_protocolChars
Will be set to 43 if protocol 1, and set to 51 if protocol 2.
INDI_NEWCALLBACK_DECL(koolanceCtrl, m_indiP_pumplvl)
~koolanceCtrl() noexcept
D'tor, declared and defined for noexcept.
virtual int appShutdown()
Shutdown the app.
pcf::IndiProperty m_indiP_fanlvl
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pcf::IndiProperty m_indiP_pumplvl
int m_fanLvl
The fan power level, 0-100.
friend class koolanceCtrl_test
float m_flowRate
The flow rate.
int recordCooler(bool force=false)
virtual int appStartup()
Startup function.
int m_pumpLvl
The pump power level, 1-10.
virtual int appLogic()
Implementation of the FSM for koolanceCtrl.
int getStatus()
Get status from controller and updated INDI.
int m_pumpRPM
The pump RPM.
int initialConnect()
Initial connection to controller.
int setPumpLvl(int lvl)
Set the pump level.
int recordTelem(const telem_cooler *)
int setFanLvl(int lvl)
Set the fan level.
pcf::IndiProperty m_indiP_status
koolanceCtrl()
Default c'tor.
int m_fanRPM
The fan RPM.
INDI_NEWCALLBACK_DECL(koolanceCtrl, m_indiP_fanlvl)
bool m_indiSetup
Whether or not INDI has been set up after initial protocol determination.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
Definition: indiMacros.hpp:247
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
Definition: indiMacros.hpp:207
@ NODEVICE
No device exists for the application to control.
Definition: stateCodes.hpp:41
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
Definition: stateCodes.hpp:37
@ 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
@ UNINITIALIZED
The application is unitialized, the default.
Definition: stateCodes.hpp:39
@ NOTCONNECTED
The application is not connected to the device or service.
Definition: stateCodes.hpp:44
int ttyReadRaw(std::vector< unsigned char > &vecRead, int &readBytes, int fd, int timeoutRead)
Read from a tty console indicated by a file-descriptor, up to a given number of bytes.
Definition: ttyIOUtils.cpp:172
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition: ttyErrors.cpp:15
int ttyRead(std::string &strRead, int bytes, int fd, int timeoutRead)
Read from a tty console indicated by a file-descriptor, until a given number of bytes are read.
Definition: ttyIOUtils.cpp:206
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
Definition: indiUtils.hpp:95
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
Definition: dm.hpp:24
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
Definition: logPriority.hpp:37
A device which saves telemetry.
Definition: telemeter.hpp:52
int appShutdown()
Perform telemeter application shutdown.
Definition: telemeter.hpp:259
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
Definition: telemeter.hpp:208
int appLogic()
Perform telemeter application logic.
Definition: telemeter.hpp:253
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Definition: telemeter.hpp:195
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Definition: telemeter.hpp:266
Software ERR log entry.
Log entry recording the build-time git state.
A USB device as a TTY device.
Definition: usbDevice.hpp:33
std::string m_deviceName
The device path name, e.g. /dev/ttyUSB0.
Definition: usbDevice.hpp:40
int m_fileDescrip
The file descriptor.
Definition: usbDevice.hpp:42
int connect()
Connect to the device.
Definition: usbDevice.cpp:108
int getDeviceName()
Get the device name from udev using the vendor, product, and serial number.
Definition: usbDevice.cpp:103
std::string m_idProduct
The product id 4-digit code.
Definition: usbDevice.hpp:35
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the USB section.
Definition: usbDevice.cpp:24
std::string m_serial
The serial number.
Definition: usbDevice.hpp:36
int loadConfig(mx::app::appConfigurator &config)
Load the USB section from an application configurator.
Definition: usbDevice.cpp:34
speed_t m_baudRate
The baud rate specification.
Definition: usbDevice.hpp:38
std::string m_idVendor
The vendor id 4-digit code.
Definition: usbDevice.hpp:34
#define TTY_E_NODEVNAMES
Definition: ttyErrors.hpp:28
#define TTY_E_DEVNOTFOUND
Definition: ttyErrors.hpp:30