API
trippLitePDU.hpp
Go to the documentation of this file.
1 /** \file trippLitePDU.hpp
2  * \brief The MagAO-X Tripp Lite Power Distribution Unit controller.
3  *
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  * \ingroup trippLitePDU_files
7  */
8 
9 #ifndef trippLitePDU_hpp
10 #define trippLitePDU_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 #ifdef XWC_SIM_MODE
17 
19 
20 #endif
21 
22 /** \defgroup trippLitePDU Tripp Lite PDU
23  * \brief Control of MagAO-X Tripp Lite PDUs.
24  *
25  * <a href="../handbook/operating/software/apps/trippLitePDU.html">Application Documentation</a>
26  *
27  * \ingroup apps
28  *
29  */
30 
31 /** \defgroup trippLitePDU_files Tripp Lite PDU Files
32  * \ingroup trippLitePDU
33  */
34 
35 namespace MagAOX
36 {
37 namespace app
38 {
39 
40 /// MagAO-X application to control a Tripp Lite power distribution unit (PDU).
41 /** The device outlets are organized into channels. See \ref dev::outletController for details of configuring the channels.
42  *
43  * The line frequency and voltage, and the total load on the PDU, are monitored.
44  *
45  * \todo need username and secure password handling
46  * \todo need to recognize signals in tty polls and not return errors, etc.
47  * \todo begin logging freq/volt/amps telemetry
48  * \todo research load warnings
49  * \todo tests for parser
50  * \todo test for load warnings
51  * \todo load warnings/crit values can be logged on parse errors -- make this an issue
52  * \todo segfaults if device can not be reached on network -- make this an issue
53  *
54  * \ingroup trippLitePDU
55  */
56 class trippLitePDU : public MagAOXApp<>, public dev::outletController<trippLitePDU>, public dev::ioDevice
57 {
58 
59 protected:
60 
61  std::string m_deviceAddr; ///< The device address
62  std::string m_devicePort; ///< The device port
63  std::string m_deviceUsername; ///< The login username for this device
64  std::string m_devicePassFile; ///< The login password for this device
65  int m_deviceVersion {0}; ///< Version 0 = the old PDUs, version 1 = new PDUMH15NET2LX, which is a new login procedure to get to the CLI.
66 
67  float m_freqLowWarn {59}; ///< The low-frequency warning threshold
68  float m_freqHighWarn {61}; ///< The high-frequency warning threshold
69 
70  float m_freqLowAlert {58}; ///< The low-frequency alert threshold
71  float m_freqHighAlert {62}; ///< The high-frequency alert threshold
72 
73  float m_freqLowEmerg {57}; ///< The low-frequency emergency threshold
74  float m_freqHighEmerg {63}; ///< The high-frequency emergency threshold
75 
76  float m_voltLowWarn {105}; ///< The low-voltage warning threshold
77  float m_voltHighWarn {125}; ///< The high-voltage warning threshold
78 
79  float m_voltLowAlert {101}; ///< The low-voltage alert threshold
80  float m_voltHighAlert {126}; ///< The high-voltage alert threshold
81 
82  float m_voltLowEmerg {99}; ///< The low-voltage emergency threshold
83  float m_voltHighEmerg {128}; ///< The high-voltage emergency threshold
84 
85  float m_currWarn {15}; ///< The high-current warning threshold
86  float m_currAlert {16}; ///< The high-current alert threshold
87  float m_currEmerg {20}; ///< The high-current emergency threshold
88 
89  #ifndef XWC_SIM_MODE
90  tty::telnetConn m_telnetConn; ///< The telnet connection manager
91  #endif
92 
93  std::string m_status; ///< The device status
94  float m_frequency {0}; ///< The line frequency reported by the device.
95  float m_voltage {0}; ///< The line voltage reported by the device.
96  float m_current {0}; ///< The current being reported by the device.
97 
98 public:
99 
100  /// Default c'tor.
101  trippLitePDU();
102 
103  /// D'tor, declared and defined for noexcept.
104  ~trippLitePDU() noexcept
105  {}
106 
107  /** \name MagAOXApp Interface
108  *
109  * @{
110  */
111 
112  /// Setup the configuration system (called by MagAOXApp::setup())
113  virtual void setupConfig();
114 
115  /// load the configuration system results (called by MagAOXApp::setup())
116  virtual void loadConfig();
117 
118  /// Startup functions
119  /** Setsup the INDI vars.
120  * Checks if the device was found during loadConfig.
121  */
122  virtual int appStartup();
123 
124  /// Implementation of the FSM for the tripp lite PDU.
125  virtual int appLogic();
126 
127  /// Do any needed shutdown tasks. Currently nothing in this app.
128  virtual int appShutdown();
129 
130  ///@}
131 
132  /** \name outletController Interface
133  *
134  * @{
135  */
136 
137  /// Update a single outlet state
138  /** For the trippLitePDU this isn't possible for a single outlet, so this calls updateOutletStates.
139  *
140  * \returns 0 on success
141  * \returns -1 on error
142  */
143  virtual int updateOutletState( int outletNum /**< [in] the outlet number to update */);
144 
145  /// Queries the device to find the state of each outlet, as well as other parameters.
146  /** Sends `devstatus` to the device, and parses the result.
147  *
148  * \returns 0 on success
149  * \returns -1 on error
150  */
151  virtual int updateOutletStates();
152 
153  /// Turn on an outlet.
154  /**
155  * \returns 0 on success
156  * \returns -1 on error
157  */
158  virtual int turnOutletOn( int outletNum /**< [in] the outlet number to turn on */);
159 
160  /// Turn off an outlet.
161  /**
162  * \returns 0 on success
163  * \returns -1 on error
164  */
165  virtual int turnOutletOff( int outletNum /**< [in] the outlet number to turn off */);
166 
167  ///@}
168 
169  /** \name Device Interface
170  *
171  * These functions invoke the simulator code when enabled.
172  *
173  * @{
174  */
175  int devConnect();
176 
177  int devLogin();
178 
179  void devPostLogin();
180 
181  int devStatus(std::string & strRead);
182 
183  /// Parse the PDU devstatus response.
184  /**
185  * \returns 0 on success
186  * \returns <0 on error, with value indicating location of error.
187  */
188  int parsePDUStatus( std::string & strRead );
189 
190  ///@}
191 
193 
194 protected:
195 
196  //declare our properties
197  pcf::IndiProperty m_indiP_status; ///< The device's status string
198  pcf::IndiProperty m_indiP_load; ///< The line and load characteristics
199 
200 
201 #ifdef XWC_SIM_MODE
202 
203 public:
204 
205  trippLitePDU_simulator m_simulator;
206 
207 #endif
208 
209 };
210 
211 trippLitePDU::trippLitePDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
212 {
213  m_firstOne = true;
215  m_loopPause=2000000000;//Default to 2 sec loop pause to lessen the load on the PDUs.
216 
217  return;
218 }
219 
221 {
222  config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
223  config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
224  config.add("device.username", "u", "device.username", argType::Required, "device", "username", false, "string", "The device login username.");
225  config.add("device.passfile", "", "device.passfile", argType::Required, "device", "passfile", false, "string", "The device login password file (relative to secrets dir).");
226  config.add("device.powerAlertVersion", "", "device.powerAlertVersion", argType::Required, "device", "powerAlertVersion", false, "int", "The device network interface version. 0 is PDU..., 1 is newer LX platform.");
227 
229 
230  config.add("limits.freqLowWarn", "", "limits.freqLowWarn", argType::Required, "limits", "freqLowWarn", false, "int", "The low-frequency warning threshold");
231  config.add("limits.freqHighWarn", "", "limits.freqHighWarn", argType::Required, "limits", "freqHighWarn", false, "int", "The high-frequency warning threshold");
232  config.add("limits.freqLowAlert", "", "limits.freqLowAlert", argType::Required, "limits", "freqLowAlert", false, "int", "The low-frequency alert threshold");
233  config.add("limits.freqHighAlert", "", "limits.freqHighAlert", argType::Required, "limits", "freqHighAlert", false, "int", "The high-frequency alert threshold");
234  config.add("limits.freqLowEmerg", "", "limits.freqLowEmerg", argType::Required, "limits", "freqLowEmerg", false, "int", "The low-frequency emergency threshold");
235  config.add("limits.freqHighEmerg", "", "limits.freqHighEmerg", argType::Required, "limits", "freqHighEmerg", false, "int", "The high-frequency emergency threshold");
236 
237  config.add("limits.voltLowWarn", "", "limits.voltLowWarn", argType::Required, "limits", "voltLowWarn", false, "int", "The low-voltage warning threshold");
238  config.add("limits.voltHighWarn", "", "limits.voltHighWarn", argType::Required, "limits", "voltHighWarn", false, "int", "The high-voltage warning threshold");
239  config.add("limits.voltLowAlert", "", "limits.voltLowAlert", argType::Required, "limits", "voltLowAlert", false, "int", "The low-voltage alert threshold");
240  config.add("limits.voltHighAlert", "", "limits.voltHighAlert", argType::Required, "limits", "voltHighAlert", false, "int", "The high-voltage alert threshold");
241  config.add("limits.voltLowEmerg", "", "limits.voltLowEmerg", argType::Required, "limits", "voltLowEmerg", false, "int", "The low-voltage emergency threshold");
242  config.add("limits.voltHighEmerg", "", "limits.voltHighEmerg", argType::Required, "limits", "voltHighEmerg", false, "int", "The high-voltage emergency threshold");
243 
244  config.add("limits.currWarn", "", "limits.currWarn", argType::Required, "limits", "currWarn", false, "int", "The high-current warning threshold");
245  config.add("limits.currAlert", "", "limits.currAlert", argType::Required, "limits", "currAlert", false, "int", "The high-current alert threshold");
246  config.add("limits.currEmerg", "", "limits.currEmerg", argType::Required, "limits", "currEmerg", false, "int", "The high-current emergency threshold");
247 
249 
250 }
251 
252 
254 {
255  config(m_deviceAddr, "device.address");
256  config(m_devicePort, "device.port");
257  config(m_deviceUsername, "device.username");
258  config(m_devicePassFile, "device.passfile");
259  config(m_deviceVersion, "device.powerAlertVersion");
260 
262 
263  config(m_freqLowWarn, "limits.freqLowWarn");
264  config(m_freqHighWarn, "limits.freqHighWarn");
265  config(m_freqLowAlert, "limits.freqLowAlert");
266  config(m_freqHighAlert, "limits.freqHighAlert");
267  config(m_freqLowEmerg, "limits.freqLowEmerg");
268  config(m_freqHighEmerg, "limits.freqHighEmerg");
269 
270  config(m_voltLowWarn, "limits.voltLowWarn");
271  config(m_voltHighWarn, "limits.voltHighWarn");
272  config(m_voltLowAlert, "limits.voltLowAlert");
273  config(m_voltHighAlert, "limits.voltHighAlert");
274  config(m_voltLowEmerg, "limits.voltLowEmerg");
275  config(m_voltHighEmerg, "limits.voltHighEmerg");
276 
277  config(m_currWarn, "limits.currWarn");
278  config(m_currAlert, "limits.currAlert");
279  config(m_currEmerg, "limits.currEmerg");
280 
282 
283 
284 }
285 
287 {
288  #ifdef XWC_SIM_MODE
289  log<text_log>("XWC_SIM_MODE active");
290  #endif
291 
292  // set up the INDI properties
293  REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
294  m_indiP_status.add (pcf::IndiElement("value"));
295 
296  REG_INDI_NEWPROP_NOCB(m_indiP_load, "load", pcf::IndiProperty::Number);
297  m_indiP_load.add (pcf::IndiElement("frequency"));
298  m_indiP_load.add (pcf::IndiElement("voltage"));
299  m_indiP_load.add (pcf::IndiElement("current"));
300 
302  {
303  return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
304  }
305 
307 
308  return 0;
309 }
310 
312 {
314  {
315  static int lastrv = 0; //Used to handle a change in error within the same state. Make general?
316  static int lasterrno = 0;
317 
318  int rv = devConnect();
319 
320  if(rv == 0)
321  {
323 
324  if(!stateLogged())
325  {
326  std::string logs = "Connected to " + m_deviceAddr + ":" + m_devicePort;
327  log<text_log>(logs);
328  }
329  lastrv = rv;
330  lasterrno = errno;
331  }
332  else
333  {
334  if(!stateLogged())
335  {
336  log<text_log>({"Failed to connect to " + m_deviceAddr + ":" + m_devicePort}, logPrio::LOG_ERROR);
337  }
338  if( rv != lastrv )
339  {
340  log<software_error>( {__FILE__,__LINE__, 0, rv, tty::ttyErrorString(rv)} );
341  lastrv = rv;
342  }
343  if( errno != lasterrno )
344  {
345  log<software_error>( {__FILE__,__LINE__, errno});
346  lasterrno = errno;
347  }
348  return 0;
349  }
350  }
351 
352  if( state() == stateCodes::CONNECTED )
353  {
354  int rv = devLogin();
355 
356  if(rv == 0)
357  {
359  }
360  else
361  {
362  if(rv == TELNET_E_LOGINTIMEOUT)
363  {
365  log<text_log>("login timedout", logPrio::LOG_ERROR);
366  return 0;
367  }
368 
370  log<text_log>("login failure", logPrio::LOG_CRITICAL);
371  return -1;
372  }
373  }
374 
375  if(state() == stateCodes::LOGGEDIN)
376  {
377  devPostLogin();
378 
380  }
381 
382  if(state() == stateCodes::READY)
383  {
384  std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
385 
386  if( !lock.owns_lock())
387  {
388  return 0;
389  }
390 
391  int rv = updateOutletStates();
392 
393  if(rv < 0) return log<software_error,-1>({__FILE__, __LINE__});
394 
396 
397  return 0;
398  }
399 
401  log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
402  return -1;
403 
404 }
405 
407 {
408  //don't bother
409  return 0;
410 }
411 
413 {
414  static_cast<void>(outletNum);
415 
416  return updateOutletStates(); //We can't do just one.
417 }
418 
419 
421 {
422  int rv;
423  std::string strRead;
424 
425  rv = devStatus(strRead);
426 
427  if(rv < 0 )
428  {
429  log<software_error>({__FILE__, __LINE__, "error getting device status"});
431  return 0;
432  }
433 
434  if(rv > 0)
435  {
436  return 0; //this means the re-read was successful, but we don't want to parse this time.
437  }
438 
439  rv = parsePDUStatus( strRead);
440 
441  if(rv == 0)
442  {
444 
446 
448 
450 
452  }
453  else
454  {
455  log<software_error>({__FILE__, __LINE__, 0, rv, "parse error"});
456  }
457 
458  return 0;
459 }
460 
461 int trippLitePDU::turnOutletOn( int outletNum )
462 {
463  std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
464 
465  #ifndef XWC_SIM_MODE
466  std::string cmd = "loadctl on -o ";
467  cmd += mx::ioutils::convertToString<int>(outletNum+1); //Internally 0 counted, device starts at 1.
468  cmd += " --force\r";
469 
470  int rv = m_telnetConn.writeRead( cmd, true, m_writeTimeout, m_readTimeout);
471 
472  #else
473 
474  int rv = m_simulator.turnOutletOn(outletNum);
475 
476  #endif
477 
478  if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
479 
480  return 0;
481 }
482 
483 int trippLitePDU::turnOutletOff( int outletNum )
484 {
485  std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
486 
487  #ifndef XWC_SIM_MODE
488  std::string cmd = "loadctl off -o ";
489  cmd += mx::ioutils::convertToString<int>(outletNum+1); //Internally 0 counted, device starts at 1.
490  cmd += " --force\r";
491 
492  int rv = m_telnetConn.writeRead( cmd, true, m_writeTimeout, m_readTimeout);
493 
494  #else
495 
496  int rv = m_simulator.turnOutletOff(outletNum);
497 
498  #endif
499 
500  if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
501 
502  return 0;
503 }
504 
506 {
507  #ifndef XWC_SIM_MODE
508 
510 
511  #else
512 
513  return m_simulator.connect(m_deviceAddr, m_devicePort);
514 
515  #endif
516 }
517 
519 {
520  #ifndef XWC_SIM_MODE
521 
522  //Newer version of power alert changed login (at least the first one)
523  if(m_deviceVersion > 0)
524  {
525  m_telnetConn.m_usernamePrompt = "login:";
526  m_telnetConn.m_prompt = ">>";
527  }
528 
529  return m_telnetConn.login("localadmin", "localadmin");
530 
531  #else
532 
533  return m_simulator.login("localadmin", "localadmin");
534 
535  #endif
536 }
537 
539 {
540 
541  #ifndef XWC_SIM_MODE
542 
543  //For newer version of power alert we need to select C.L.I.
544  if(m_deviceVersion > 0)
545  {
547  m_telnetConn.m_prompt = "$> ";
548  }
549 
550  #else
551 
552  m_simulator.postLogin();
553 
554  #endif
555 }
556 
557 int trippLitePDU::devStatus(std::string & strRead)
558 {
559  #ifndef XWC_SIM_MODE
560 
561  int rv = m_telnetConn.writeRead("devstatus\n", true, m_writeTimeout, m_readTimeout);
562 
563  strRead = m_telnetConn.m_strRead;
564 
566  {
567  rv = m_telnetConn.read(m_readTimeout, false);
568 
569  if( rv < 0 )
570  {
571  log<software_error>({__FILE__, __LINE__, 0, rv, "devstatus timeout, timed out on re-read: " + tty::ttyErrorString(rv)});
572  return -1;
573  }
574 
575  log<text_log>("devstatus timeout, re-read successful");
576 
577  return 1;
578  }
579  else if(rv < 0 )
580  {
581  log<software_error>({__FILE__, __LINE__, 0, rv, tty::ttyErrorString(rv)});
582  return -1;
583  }
584 
585  return 0;
586 
587  #else
588 
589  return m_simulator.devStatus(strRead);
590 
591  #endif
592 }
593 
594 int trippLitePDU::parsePDUStatus( std::string & strRead )
595 {
596  size_t curpos = 0;
597 
598  curpos = strRead.find_first_of("\r\n", curpos);
599 
600  std::string sstr;
601 
602  while(curpos < strRead.size())
603  {
604  size_t eol = strRead.find_first_of("\r\n", curpos);
605 
606  if(eol == std::string::npos) eol = strRead.size();
607 
608  if(eol == curpos)
609  {
610  curpos = eol + 1;
611  continue;
612  }
613 
614  sstr = strRead.substr(curpos, eol-curpos);
615  curpos = eol + 1;
616 
617  if(sstr[0] == '-' || sstr[0] == '0' || sstr[0] == 'L' || sstr[0] == ' ' || sstr[0] == 'D' || sstr[0] == '$') continue;
618 
619  if(sstr[0] == 'I')
620  {
621  if(sstr[6] == 'V')
622  {
623  size_t begin = sstr.find(' ',6);
624  if(begin == std::string::npos)
625  {
626  return -1;
627  }
628 
629  begin = sstr.find_first_not_of(' ', begin);
630  if(begin == std::string::npos)
631  {
632  return -2;
633  }
634 
635  size_t end = sstr.find('V', begin);
636  if(end == std::string::npos)
637  {
638  return -3;
639  }
640 
641  float V = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
642 
643  m_voltage = V;
644  }
645 
646  else if(sstr[6] == 'F')
647  {
648  size_t begin = sstr.find(' ',6);
649  if(begin == std::string::npos)
650  {
651  return -4;
652  }
653 
654  begin = sstr.find_first_not_of(' ', begin);
655  if(begin == std::string::npos)
656  {
657  return -5;
658  }
659 
660  size_t end = sstr.find('H', begin);
661  if(end == std::string::npos)
662  {
663  return -6;
664  }
665 
666  float F = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
667 
668  m_frequency = F;
669  }
670  else return -1;
671  }
672  else if(sstr[0] == 'O')
673  {
674  if(sstr[7] == 'C')
675  {
676  size_t begin = sstr.find(' ',7);
677  if(begin == std::string::npos)
678  {
679  return -7;
680  }
681 
682  begin = sstr.find_first_not_of(' ', begin);
683  if(begin == std::string::npos)
684  {
685  return -8;
686  }
687 
688  size_t end = sstr.find('A', begin);
689  if(end == std::string::npos)
690  {
691  return -9;
692  }
693 
694  float C = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
695 
696  m_current = C;
697  }
698  else if(sstr[8] == 'O')
699  {
700  std::vector<int> outletStates(m_outletStates.size(),OUTLET_STATE_OFF);
701 
702  size_t begin = sstr.find(' ',8);
703  if(begin == std::string::npos)
704  {
705  return -10;
706  }
707 
708  begin = sstr.find_first_not_of(' ', begin);
709 
710  if(begin == std::string::npos)
711  {
712  return -11;
713  }
714 
715  while(begin < sstr.size())
716  {
717  size_t end = sstr.find(' ', begin);
718  if(end == std::string::npos)
719  {
720  end = sstr.size();
721  }
722 
723  int onum = atoi(sstr.substr(begin, end-begin).c_str());
724 
725  if(onum > 0 && onum < 9)
726  {
727  outletStates[onum-1] = OUTLET_STATE_ON; //this outlet is on.
728  }
729  begin = sstr.find_first_not_of(' ', end+1);
730  }
731 
732  for(size_t i=0;i<m_outletStates.size();++i)
733  {
734  m_outletStates[i]=outletStates[i];
735  }
736  }
737  else if( sstr[7] == 'V' || sstr[7] == 'F')
738  {
739  continue;
740  }
741  else
742  {
743  return -12;
744  }
745  }
746  else
747  {
748  return -13;
749  }
750  }
751 
752  return 0;
753 }
754 
756 {
758  {
759  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
760  std::to_string(m_freqLowEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
761  }
762  else if (m_frequency >= m_freqHighEmerg)
763  {
764  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
765  std::to_string(m_freqHighEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
766  }
767  else if (m_frequency <= m_freqLowAlert)
768  {
769  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
770  std::to_string(m_freqLowAlert) + " Hz.", logPrio::LOG_ALERT);
771  }
772  else if (m_frequency >= m_freqHighAlert)
773  {
774  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
775  std::to_string(m_freqHighAlert) + " Hz.", logPrio::LOG_ALERT);
776  }
777  else if(m_frequency <= m_freqLowWarn)
778  {
779  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
780  std::to_string(m_freqLowWarn) + " Hz.", logPrio::LOG_WARNING);
781  }
782  else if (m_frequency >= m_freqHighWarn)
783  {
784  log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
785  std::to_string(m_freqHighWarn) + " Hz.", logPrio::LOG_WARNING);
786  }
787 
788  if (m_voltage <= m_voltLowEmerg)
789  {
790  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
791  std::to_string(m_voltLowEmerg) + " V.", logPrio::LOG_EMERGENCY);
792  }
793  else if (m_voltage >= m_voltHighEmerg)
794  {
795  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
796  std::to_string(m_voltHighEmerg) + " V.", logPrio::LOG_EMERGENCY);
797  }
798  else if (m_voltage <= m_voltLowAlert)
799  {
800  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
801  std::to_string(m_voltLowAlert) + " V.", logPrio::LOG_ALERT);
802  }
803  else if (m_voltage >= m_voltHighAlert)
804  {
805  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
806  std::to_string(m_voltHighAlert) + " V.", logPrio::LOG_ALERT);
807  }
808  else if(m_voltage <= m_voltLowWarn)
809  {
810  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
811  std::to_string(m_voltLowWarn) + " V.", logPrio::LOG_WARNING);
812  }
813  else if (m_voltage >= m_voltHighWarn)
814  {
815  log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
816  std::to_string(m_voltHighWarn) + " V.", logPrio::LOG_WARNING);
817  }
818 
819  if (m_current >= m_currEmerg)
820  {
821  log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
822  std::to_string(m_currEmerg) + " A.", logPrio::LOG_EMERGENCY);
823  }
824  else if (m_current >= m_currAlert)
825  {
826  log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
827  std::to_string(m_currAlert) + " A.", logPrio::LOG_ALERT);
828  }
829  else if (m_current >= m_currWarn)
830  {
831  log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
832  std::to_string(m_currWarn) + " A.", logPrio::LOG_WARNING);
833  }
834 }
835 
836 } //namespace app
837 } //namespace MagAOX
838 
839 #endif //trippLitePDU_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
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 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
MagAO-X application to control a Tripp Lite power distribution unit (PDU).
float m_voltage
The line voltage reported by the device.
float m_currWarn
The high-current warning threshold.
std::string m_status
The device status.
std::string m_deviceUsername
The login username for this device.
int devStatus(std::string &strRead)
float m_currAlert
The high-current alert threshold.
float m_voltHighAlert
The high-voltage alert threshold.
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
pcf::IndiProperty m_indiP_status
The device's status string.
pcf::IndiProperty m_indiP_load
The line and load characteristics.
virtual int turnOutletOn(int outletNum)
Turn on an outlet.
virtual int updateOutletStates()
Queries the device to find the state of each outlet, as well as other parameters.
virtual int appLogic()
Implementation of the FSM for the tripp lite PDU.
float m_freqLowAlert
The low-frequency alert threshold.
float m_freqHighEmerg
The high-frequency emergency threshold.
float m_frequency
The line frequency reported by the device.
float m_voltLowWarn
The low-voltage warning threshold.
float m_voltLowAlert
The low-voltage alert threshold.
int m_deviceVersion
Version 0 = the old PDUs, version 1 = new PDUMH15NET2LX, which is a new login procedure to get to the...
std::string m_devicePassFile
The login password for this device.
float m_voltHighEmerg
The high-voltage emergency threshold.
std::string m_deviceAddr
The device address.
virtual int appStartup()
Startup functions.
float m_currEmerg
The high-current emergency threshold.
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
~trippLitePDU() noexcept
D'tor, declared and defined for noexcept.
float m_freqHighWarn
The high-frequency warning threshold.
float m_freqLowWarn
The low-frequency warning threshold.
trippLitePDU()
Default c'tor.
float m_voltHighWarn
The high-voltage warning threshold.
float m_voltLowEmerg
The low-voltage emergency threshold.
virtual int turnOutletOff(int outletNum)
Turn off an outlet.
virtual int updateOutletState(int outletNum)
Update a single outlet state.
tty::telnetConn m_telnetConn
The telnet connection manager.
float m_current
The current being reported by the device.
float m_freqLowEmerg
The low-frequency emergency threshold.
std::string m_devicePort
The device port.
float m_freqHighAlert
The high-frequency alert threshold.
int parsePDUStatus(std::string &strRead)
Parse the PDU devstatus response.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
Definition: indiMacros.hpp:247
@ 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
@ LOGGEDIN
The application has logged into the device or service.
Definition: stateCodes.hpp:46
@ 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
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition: ttyErrors.cpp:15
Definition: dm.hpp:24
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
Definition: logPriority.hpp:37
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Definition: logPriority.hpp:40
constexpr static logPrioT LOG_ALERT
This should only be used if some action is required by operators to keep the system safe.
Definition: logPriority.hpp:34
constexpr static logPrioT LOG_EMERGENCY
Normal operations of the entire system should be shut down immediately.
Definition: logPriority.hpp:31
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
Definition: logPriority.hpp:43
#define OUTLET_STATE_OFF
#define OUTLET_STATE_ON
An input/output capable device.
Definition: ioDevice.hpp:27
unsigned m_writeTimeout
The write timeout [msec].
Definition: ioDevice.hpp:29
int loadConfig(mx::app::appConfigurator &config)
Load the device section from an application configurator.
Definition: ioDevice.cpp:28
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the device section.
Definition: ioDevice.cpp:20
unsigned m_readTimeout
The read timeout [msec].
Definition: ioDevice.hpp:28
A generic outlet controller.
int updateINDI()
Update the INDI properties for this device controller.
bool m_firstOne
Flag is true if the first outlet is numbered 1, otherwise assumes starting at 0.
int loadConfig(mx::app::appConfigurator &config)
Load the [channel] sections from an application configurator.
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for an outletController.
int setNumberOfOutlets(int numOuts)
Sets the number of outlets. This should be called by the derived class constructor.
std::vector< int > m_outletStates
The current states of each outlet. These MUST be updated by derived classes in the overridden updated...
Software ERR log entry.
A simple text log, a string-type log.
Definition: text_log.hpp:24
A Telnet connection manager, wrapping libtelnet.
Definition: telnetConn.hpp:81
int login(const std::string &username, const std::string &password)
Manage the login process on this device.
Definition: telnetConn.cpp:90
std::string m_usernamePrompt
The device's username entry prompt, used for managing login.
Definition: telnetConn.hpp:87
std::string m_strRead
The accumulated string read from the device.
Definition: telnetConn.hpp:113
std::string m_prompt
The device's prompt, used for detecting end of transmission.
Definition: telnetConn.hpp:92
int writeRead(const std::string &strWrite, bool swallowEcho, int timeoutWrite, int timeoutRead)
Write to a telnet connection, then get the reply.
Definition: telnetConn.cpp:294
int read(const std::string &eot, int timeoutRead, bool clear=true)
Read from a telnet connection, until end-of-transmission string is read.
Definition: telnetConn.cpp:223
int connect(const std::string &host, const std::string &port)
Connect to the device.
Definition: telnetConn.cpp:31
The MagAO-X Tripp Lite Power Distribution Unit ontroller Simulator.
#define TTY_E_TIMEOUTONREAD
Definition: ttyErrors.hpp:27
#define TTY_E_TIMEOUTONREADPOLL
Definition: ttyErrors.hpp:24
#define TELNET_E_LOGINTIMEOUT
Definition: ttyErrors.hpp:40