API
 
Loading...
Searching...
No Matches
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
35namespace MagAOX
36{
37namespace 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 */
56class trippLitePDU : public MagAOXApp<>, public dev::outletController<trippLitePDU>, public dev::ioDevice
57{
58
59protected:
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
98public:
99
100 /// Default c'tor.
101 trippLitePDU();
102
103 /// D'tor, declared and defined for noexcept.
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
194protected:
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
203public:
204
206
207#endif
208
209};
210
211trippLitePDU::trippLitePDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
212{
213 m_firstOne = true;
214 m_stateDelay = 5;
215
217 m_loopPause=2000000000;//Default to 2 sec loop pause to lessen the load on the PDUs.
218
219 return;
220}
221
223{
224 config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
225 config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
226 config.add("device.username", "u", "device.username", argType::Required, "device", "username", false, "string", "The device login username.");
227 config.add("device.passfile", "", "device.passfile", argType::Required, "device", "passfile", false, "string", "The device login password file (relative to secrets dir).");
228 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.");
229
231
232 config.add("limits.freqLowWarn", "", "limits.freqLowWarn", argType::Required, "limits", "freqLowWarn", false, "int", "The low-frequency warning threshold");
233 config.add("limits.freqHighWarn", "", "limits.freqHighWarn", argType::Required, "limits", "freqHighWarn", false, "int", "The high-frequency warning threshold");
234 config.add("limits.freqLowAlert", "", "limits.freqLowAlert", argType::Required, "limits", "freqLowAlert", false, "int", "The low-frequency alert threshold");
235 config.add("limits.freqHighAlert", "", "limits.freqHighAlert", argType::Required, "limits", "freqHighAlert", false, "int", "The high-frequency alert threshold");
236 config.add("limits.freqLowEmerg", "", "limits.freqLowEmerg", argType::Required, "limits", "freqLowEmerg", false, "int", "The low-frequency emergency threshold");
237 config.add("limits.freqHighEmerg", "", "limits.freqHighEmerg", argType::Required, "limits", "freqHighEmerg", false, "int", "The high-frequency emergency threshold");
238
239 config.add("limits.voltLowWarn", "", "limits.voltLowWarn", argType::Required, "limits", "voltLowWarn", false, "int", "The low-voltage warning threshold");
240 config.add("limits.voltHighWarn", "", "limits.voltHighWarn", argType::Required, "limits", "voltHighWarn", false, "int", "The high-voltage warning threshold");
241 config.add("limits.voltLowAlert", "", "limits.voltLowAlert", argType::Required, "limits", "voltLowAlert", false, "int", "The low-voltage alert threshold");
242 config.add("limits.voltHighAlert", "", "limits.voltHighAlert", argType::Required, "limits", "voltHighAlert", false, "int", "The high-voltage alert threshold");
243 config.add("limits.voltLowEmerg", "", "limits.voltLowEmerg", argType::Required, "limits", "voltLowEmerg", false, "int", "The low-voltage emergency threshold");
244 config.add("limits.voltHighEmerg", "", "limits.voltHighEmerg", argType::Required, "limits", "voltHighEmerg", false, "int", "The high-voltage emergency threshold");
245
246 config.add("limits.currWarn", "", "limits.currWarn", argType::Required, "limits", "currWarn", false, "int", "The high-current warning threshold");
247 config.add("limits.currAlert", "", "limits.currAlert", argType::Required, "limits", "currAlert", false, "int", "The high-current alert threshold");
248 config.add("limits.currEmerg", "", "limits.currEmerg", argType::Required, "limits", "currEmerg", false, "int", "The high-current emergency threshold");
249
251
252}
253
254
256{
257 config(m_deviceAddr, "device.address");
258 config(m_devicePort, "device.port");
259 config(m_deviceUsername, "device.username");
260 config(m_devicePassFile, "device.passfile");
261 config(m_deviceVersion, "device.powerAlertVersion");
262
264
265 config(m_freqLowWarn, "limits.freqLowWarn");
266 config(m_freqHighWarn, "limits.freqHighWarn");
267 config(m_freqLowAlert, "limits.freqLowAlert");
268 config(m_freqHighAlert, "limits.freqHighAlert");
269 config(m_freqLowEmerg, "limits.freqLowEmerg");
270 config(m_freqHighEmerg, "limits.freqHighEmerg");
271
272 config(m_voltLowWarn, "limits.voltLowWarn");
273 config(m_voltHighWarn, "limits.voltHighWarn");
274 config(m_voltLowAlert, "limits.voltLowAlert");
275 config(m_voltHighAlert, "limits.voltHighAlert");
276 config(m_voltLowEmerg, "limits.voltLowEmerg");
277 config(m_voltHighEmerg, "limits.voltHighEmerg");
278
279 config(m_currWarn, "limits.currWarn");
280 config(m_currAlert, "limits.currAlert");
281 config(m_currEmerg, "limits.currEmerg");
282
284
285
286}
287
289{
290 #ifdef XWC_SIM_MODE
291 log<text_log>("XWC_SIM_MODE active");
292 #endif
293
294 // set up the INDI properties
295 REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
296 m_indiP_status.add (pcf::IndiElement("value"));
297
298 REG_INDI_NEWPROP_NOCB(m_indiP_load, "load", pcf::IndiProperty::Number);
299 m_indiP_load.add (pcf::IndiElement("frequency"));
300 m_indiP_load.add (pcf::IndiElement("voltage"));
301 m_indiP_load.add (pcf::IndiElement("current"));
302
304 {
305 return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
306 }
307
309
310 return 0;
311}
312
314{
316 {
317 static int lastrv = 0; //Used to handle a change in error within the same state. Make general?
318 static int lasterrno = 0;
319
320 int rv = devConnect();
321
322 if(rv == 0)
323 {
325
326 if(!stateLogged())
327 {
328 std::string logs = "Connected to " + m_deviceAddr + ":" + m_devicePort;
330 }
331 lastrv = rv;
333 }
334 else
335 {
336 if(!stateLogged())
337 {
338 log<text_log>({"Failed to connect to " + m_deviceAddr + ":" + m_devicePort}, logPrio::LOG_ERROR);
339 }
340 if( rv != lastrv )
341 {
343 lastrv = rv;
344 }
345 if( errno != lasterrno )
346 {
349 }
350 return 0;
351 }
352 }
353
355 {
356 int rv = devLogin();
357
358 if(rv == 0)
359 {
361 }
362 else
363 {
365 {
367 log<text_log>("login timedout", logPrio::LOG_ERROR);
368 return 0;
369 }
370
372 log<text_log>("login failure", logPrio::LOG_CRITICAL);
373 return -1;
374 }
375 }
376
378 {
379 devPostLogin();
380
382 }
383
384 if(state() == stateCodes::READY)
385 {
386 std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
387
388 if( !lock.owns_lock())
389 {
390 return 0;
391 }
392
393 int rv = updateOutletStates();
394
395 if(rv < 0) return log<software_error,-1>();
396
398
399 return 0;
400 }
401
403 log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
404 return -1;
405
406}
407
409{
410 //don't bother
411 return 0;
412}
413
415{
416 static_cast<void>(outletNum);
417
418 return updateOutletStates(); //We can't do just one.
419}
420
421
423{
424 int rv;
425 std::string strRead;
426
428
429 if(rv < 0 )
430 {
431 log<software_error>("error getting device status");
433 return 0;
434 }
435
436 if(rv > 0)
437 {
438 return 0; //this means the re-read was successful, but we don't want to parse this time.
439 }
440
442
443 if(rv == 0)
444 {
446
448
450
452
454 }
455 else
456 {
457 log<software_error>({0, rv, "parse error"});
458 }
459
460 return 0;
461}
462
463int trippLitePDU::turnOutletOn( int outletNum )
464{
465 std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
466
467 #ifndef XWC_SIM_MODE
468 std::string cmd = std::format("loadctl on -o {} --force\r", (outletNum+1)); //Internally 0 counted, device starts at 1.
469
471
472 #else
473
474 int rv = m_simulator.turnOutletOn(outletNum);
475
476 #endif
477
478 if(rv < 0)
479 {
480 return log<software_error, -1>({0, rv, "telnet error"});
481 }
482
483 return 0;
484}
485
486int trippLitePDU::turnOutletOff( int outletNum )
487{
488 std::lock_guard<std::mutex> guard(m_indiMutex); //Lock the mutex before doing anything
489
490 #ifndef XWC_SIM_MODE
491 std::string cmd = std::format("loadctl off -o {} --force\r", (outletNum+1)); //Internally 0 counted, device starts at 1.
492
494
495 #else
496
497 int rv = m_simulator.turnOutletOff(outletNum);
498
499 #endif
500
501 if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
502
503 return 0;
504}
505
507{
508 #ifndef XWC_SIM_MODE
509
511
512 #else
513
514 return m_simulator.connect(m_deviceAddr, m_devicePort);
515
516 #endif
517}
518
520{
521 #ifndef XWC_SIM_MODE
522
523 //Newer version of power alert changed login (at least the first one)
524 if(m_deviceVersion > 0)
525 {
527 m_telnetConn.m_prompt = ">>";
528 }
529
530 return m_telnetConn.login("localadmin", "localadmin");
531
532 #else
533
534 return m_simulator.login("localadmin", "localadmin");
535
536 #endif
537}
538
540{
541
542 #ifndef XWC_SIM_MODE
543
544 //For newer version of power alert we need to select C.L.I.
545 if(m_deviceVersion > 0)
546 {
548 m_telnetConn.m_prompt = "$> ";
549 }
550
551 #else
552
553 m_simulator.postLogin();
554
555 #endif
556}
557
558int trippLitePDU::devStatus(std::string & strRead)
559{
560 #ifndef XWC_SIM_MODE
561
562 int rv = m_telnetConn.writeRead("devstatus\n", true, m_writeTimeout, m_readTimeout);
563
565
567 {
569
570 if( rv < 0 )
571 {
572 log<software_error>({__FILE__, __LINE__, 0, rv, "devstatus timeout, timed out on re-read: " + tty::ttyErrorString(rv)});
573 return -1;
574 }
575
576 log<text_log>("devstatus timeout, re-read successful");
577
578 return 1;
579 }
580 else if(rv < 0 )
581 {
583 return -1;
584 }
585
586 return 0;
587
588 #else
589
590 return m_simulator.devStatus(strRead);
591
592 #endif
593}
594
595int trippLitePDU::parsePDUStatus( std::string & strRead )
596{
597 size_t curpos = 0;
598
599 curpos = strRead.find_first_of("\r\n", curpos);
600
601 std::string sstr;
602
603 while(curpos < strRead.size())
604 {
605 size_t eol = strRead.find_first_of("\r\n", curpos);
606
607 if(eol == std::string::npos) eol = strRead.size();
608
609 if(eol == curpos)
610 {
611 curpos = eol + 1;
612 continue;
613 }
614
615 sstr = strRead.substr(curpos, eol-curpos);
616 curpos = eol + 1;
617
618 if(sstr[0] == '-' || sstr[0] == '0' || sstr[0] == 'L' || sstr[0] == ' ' || sstr[0] == 'D' || sstr[0] == '$') continue;
619
620 if(sstr[0] == 'I')
621 {
622 if(sstr[6] == 'V')
623 {
624 size_t begin = sstr.find(' ',6);
625 if(begin == std::string::npos)
626 {
627 return -1;
628 }
629
630 begin = sstr.find_first_not_of(' ', begin);
631 if(begin == std::string::npos)
632 {
633 return -2;
634 }
635
636 size_t end = sstr.find('V', begin);
637 if(end == std::string::npos)
638 {
639 return -3;
640 }
641
642 float V = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
643
644 m_voltage = V;
645 }
646
647 else if(sstr[6] == 'F')
648 {
649 size_t begin = sstr.find(' ',6);
650 if(begin == std::string::npos)
651 {
652 return -4;
653 }
654
655 begin = sstr.find_first_not_of(' ', begin);
656 if(begin == std::string::npos)
657 {
658 return -5;
659 }
660
661 size_t end = sstr.find('H', begin);
662 if(end == std::string::npos)
663 {
664 return -6;
665 }
666
667 float F = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
668
669 m_frequency = F;
670 }
671 else return -1;
672 }
673 else if(sstr[0] == 'O')
674 {
675 if(sstr[7] == 'C')
676 {
677 size_t begin = sstr.find(' ',7);
678 if(begin == std::string::npos)
679 {
680 return -7;
681 }
682
683 begin = sstr.find_first_not_of(' ', begin);
684 if(begin == std::string::npos)
685 {
686 return -8;
687 }
688
689 size_t end = sstr.find('A', begin);
690 if(end == std::string::npos)
691 {
692 return -9;
693 }
694
695 float C = mx::ioutils::stoT<float>( sstr.substr(begin, end-begin) );
696
697 m_current = C;
698 }
699 else if(sstr[8] == 'O')
700 {
701 std::vector<int> outletStates(m_outletStates.size(),OUTLET_STATE_OFF);
702
703 size_t begin = sstr.find(' ',8);
704 if(begin == std::string::npos)
705 {
706 return -10;
707 }
708
709 begin = sstr.find_first_not_of(' ', begin);
710
711 if(begin == std::string::npos)
712 {
713 return -11;
714 }
715
716 while(begin < sstr.size())
717 {
718 size_t end = sstr.find(' ', begin);
719 if(end == std::string::npos)
720 {
721 end = sstr.size();
722 }
723
724 int onum = atoi(sstr.substr(begin, end-begin).c_str());
725
726 if(onum > 0 && onum < 9)
727 {
728 outletStates[onum-1] = OUTLET_STATE_ON; //this outlet is on.
729 }
730 begin = sstr.find_first_not_of(' ', end+1);
731 }
732
733 for(size_t i=0;i<m_outletStates.size();++i)
734 {
736 }
737 }
738 else if( sstr[7] == 'V' || sstr[7] == 'F')
739 {
740 continue;
741 }
742 else
743 {
744 return -12;
745 }
746 }
747 else
748 {
749 return -13;
750 }
751 }
752
753 return 0;
754}
755
757{
759 {
760 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
761 std::to_string(m_freqLowEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
762 }
763 else if (m_frequency >= m_freqHighEmerg)
764 {
765 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
766 std::to_string(m_freqHighEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
767 }
768 else if (m_frequency <= m_freqLowAlert)
769 {
770 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
771 std::to_string(m_freqLowAlert) + " Hz.", logPrio::LOG_ALERT);
772 }
773 else if (m_frequency >= m_freqHighAlert)
774 {
775 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
776 std::to_string(m_freqHighAlert) + " Hz.", logPrio::LOG_ALERT);
777 }
778 else if(m_frequency <= m_freqLowWarn)
779 {
780 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
781 std::to_string(m_freqLowWarn) + " Hz.", logPrio::LOG_WARNING);
782 }
783 else if (m_frequency >= m_freqHighWarn)
784 {
785 log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
786 std::to_string(m_freqHighWarn) + " Hz.", logPrio::LOG_WARNING);
787 }
788
790 {
791 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
792 std::to_string(m_voltLowEmerg) + " V.", logPrio::LOG_EMERGENCY);
793 }
794 else if (m_voltage >= m_voltHighEmerg)
795 {
796 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
797 std::to_string(m_voltHighEmerg) + " V.", logPrio::LOG_EMERGENCY);
798 }
799 else if (m_voltage <= m_voltLowAlert)
800 {
801 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
802 std::to_string(m_voltLowAlert) + " V.", logPrio::LOG_ALERT);
803 }
804 else if (m_voltage >= m_voltHighAlert)
805 {
806 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
807 std::to_string(m_voltHighAlert) + " V.", logPrio::LOG_ALERT);
808 }
809 else if(m_voltage <= m_voltLowWarn)
810 {
811 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
812 std::to_string(m_voltLowWarn) + " V.", logPrio::LOG_WARNING);
813 }
814 else if (m_voltage >= m_voltHighWarn)
815 {
816 log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
817 std::to_string(m_voltHighWarn) + " V.", logPrio::LOG_WARNING);
818 }
819
820 if (m_current >= m_currEmerg)
821 {
822 log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
823 std::to_string(m_currEmerg) + " A.", logPrio::LOG_EMERGENCY);
824 }
825 else if (m_current >= m_currAlert)
826 {
827 log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
828 std::to_string(m_currAlert) + " A.", logPrio::LOG_ALERT);
829 }
830 else if (m_current >= m_currWarn)
831 {
832 log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
833 std::to_string(m_currWarn) + " A.", logPrio::LOG_WARNING);
834 }
835}
836
837} //namespace app
838} //namespace MagAOX
839
840#endif //trippLitePDU_hpp
The base-class for XWCTk applications.
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.
stateCodes::stateCodeT state()
Get the current state code.
unsigned long m_loopPause
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::mutex m_indiMutex
Mutex for locking INDI communications.
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.
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.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition ttyErrors.cpp:15
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:19
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
static constexpr logPrioT LOG_EMERGENCY
Normal operations of the entire system should be shut down immediately.
static constexpr logPrioT LOG_ALERT
This should only be used if some action is required by operators to keep the system safe.
#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.
double m_stateDelay
Delay to wait after changing states before allowing a new command.
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.
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
@ READY
The device is ready for operation, but is not operating.
@ LOGGEDIN
The application has logged into the device or service.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
Software ERR log entry.
A simple text log, a string-type log.
Definition text_log.hpp:24
A Telnet connection manager, wrapping libtelnet.
int login(const std::string &username, const std::string &password)
Manage the login process on this device.
std::string m_usernamePrompt
The device's username entry prompt, used for managing login.
std::string m_strRead
The accumulated string read from the device.
std::string m_prompt
The device's prompt, used for detecting end of transmission.
int writeRead(const std::string &strWrite, bool swallowEcho, int timeoutWrite, int timeoutRead)
Write to a telnet connection, then get the reply.
int read(const std::string &eot, int timeoutRead, bool clear=true)
Read from a telnet connection, until end-of-transmission string is read.
int connect(const std::string &host, const std::string &port)
Connect to the device.
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