Line data Source code
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 :
18 : #include "trippLitePDU_simulator.hpp"
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 0 : ~trippLitePDU() noexcept
105 0 : {}
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 :
192 : void updateAlarmsAndWarnings();
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 0 : trippLitePDU::trippLitePDU() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
212 : {
213 0 : m_firstOne = true;
214 0 : setNumberOfOutlets(8);
215 0 : m_loopPause=2000000000;//Default to 2 sec loop pause to lessen the load on the PDUs.
216 :
217 0 : return;
218 0 : }
219 :
220 0 : void trippLitePDU::setupConfig()
221 : {
222 0 : config.add("device.address", "a", "device.address", argType::Required, "device", "address", false, "string", "The device address.");
223 0 : config.add("device.port", "p", "device.port", argType::Required, "device", "port", false, "string", "The device port.");
224 0 : config.add("device.username", "u", "device.username", argType::Required, "device", "username", false, "string", "The device login username.");
225 0 : config.add("device.passfile", "", "device.passfile", argType::Required, "device", "passfile", false, "string", "The device login password file (relative to secrets dir).");
226 0 : 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 :
228 0 : dev::ioDevice::setupConfig(config);
229 :
230 0 : config.add("limits.freqLowWarn", "", "limits.freqLowWarn", argType::Required, "limits", "freqLowWarn", false, "int", "The low-frequency warning threshold");
231 0 : config.add("limits.freqHighWarn", "", "limits.freqHighWarn", argType::Required, "limits", "freqHighWarn", false, "int", "The high-frequency warning threshold");
232 0 : config.add("limits.freqLowAlert", "", "limits.freqLowAlert", argType::Required, "limits", "freqLowAlert", false, "int", "The low-frequency alert threshold");
233 0 : config.add("limits.freqHighAlert", "", "limits.freqHighAlert", argType::Required, "limits", "freqHighAlert", false, "int", "The high-frequency alert threshold");
234 0 : config.add("limits.freqLowEmerg", "", "limits.freqLowEmerg", argType::Required, "limits", "freqLowEmerg", false, "int", "The low-frequency emergency threshold");
235 0 : config.add("limits.freqHighEmerg", "", "limits.freqHighEmerg", argType::Required, "limits", "freqHighEmerg", false, "int", "The high-frequency emergency threshold");
236 :
237 0 : config.add("limits.voltLowWarn", "", "limits.voltLowWarn", argType::Required, "limits", "voltLowWarn", false, "int", "The low-voltage warning threshold");
238 0 : config.add("limits.voltHighWarn", "", "limits.voltHighWarn", argType::Required, "limits", "voltHighWarn", false, "int", "The high-voltage warning threshold");
239 0 : config.add("limits.voltLowAlert", "", "limits.voltLowAlert", argType::Required, "limits", "voltLowAlert", false, "int", "The low-voltage alert threshold");
240 0 : config.add("limits.voltHighAlert", "", "limits.voltHighAlert", argType::Required, "limits", "voltHighAlert", false, "int", "The high-voltage alert threshold");
241 0 : config.add("limits.voltLowEmerg", "", "limits.voltLowEmerg", argType::Required, "limits", "voltLowEmerg", false, "int", "The low-voltage emergency threshold");
242 0 : config.add("limits.voltHighEmerg", "", "limits.voltHighEmerg", argType::Required, "limits", "voltHighEmerg", false, "int", "The high-voltage emergency threshold");
243 :
244 0 : config.add("limits.currWarn", "", "limits.currWarn", argType::Required, "limits", "currWarn", false, "int", "The high-current warning threshold");
245 0 : config.add("limits.currAlert", "", "limits.currAlert", argType::Required, "limits", "currAlert", false, "int", "The high-current alert threshold");
246 0 : config.add("limits.currEmerg", "", "limits.currEmerg", argType::Required, "limits", "currEmerg", false, "int", "The high-current emergency threshold");
247 :
248 0 : dev::outletController<trippLitePDU>::setupConfig(config);
249 :
250 0 : }
251 :
252 :
253 0 : void trippLitePDU::loadConfig()
254 : {
255 0 : config(m_deviceAddr, "device.address");
256 0 : config(m_devicePort, "device.port");
257 0 : config(m_deviceUsername, "device.username");
258 0 : config(m_devicePassFile, "device.passfile");
259 0 : config(m_deviceVersion, "device.powerAlertVersion");
260 :
261 0 : dev::ioDevice::loadConfig(config);
262 :
263 0 : config(m_freqLowWarn, "limits.freqLowWarn");
264 0 : config(m_freqHighWarn, "limits.freqHighWarn");
265 0 : config(m_freqLowAlert, "limits.freqLowAlert");
266 0 : config(m_freqHighAlert, "limits.freqHighAlert");
267 0 : config(m_freqLowEmerg, "limits.freqLowEmerg");
268 0 : config(m_freqHighEmerg, "limits.freqHighEmerg");
269 :
270 0 : config(m_voltLowWarn, "limits.voltLowWarn");
271 0 : config(m_voltHighWarn, "limits.voltHighWarn");
272 0 : config(m_voltLowAlert, "limits.voltLowAlert");
273 0 : config(m_voltHighAlert, "limits.voltHighAlert");
274 0 : config(m_voltLowEmerg, "limits.voltLowEmerg");
275 0 : config(m_voltHighEmerg, "limits.voltHighEmerg");
276 :
277 0 : config(m_currWarn, "limits.currWarn");
278 0 : config(m_currAlert, "limits.currAlert");
279 0 : config(m_currEmerg, "limits.currEmerg");
280 :
281 0 : dev::outletController<trippLitePDU>::loadConfig(config);
282 :
283 :
284 0 : }
285 :
286 0 : int trippLitePDU::appStartup()
287 : {
288 : #ifdef XWC_SIM_MODE
289 0 : log<text_log>("XWC_SIM_MODE active");
290 : #endif
291 :
292 : // set up the INDI properties
293 0 : REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Text);
294 0 : m_indiP_status.add (pcf::IndiElement("value"));
295 :
296 0 : REG_INDI_NEWPROP_NOCB(m_indiP_load, "load", pcf::IndiProperty::Number);
297 0 : m_indiP_load.add (pcf::IndiElement("frequency"));
298 0 : m_indiP_load.add (pcf::IndiElement("voltage"));
299 0 : m_indiP_load.add (pcf::IndiElement("current"));
300 :
301 0 : if(dev::outletController<trippLitePDU>::setupINDI() < 0)
302 : {
303 0 : return log<text_log,-1>("Error setting up INDI for outlet control.", logPrio::LOG_CRITICAL);
304 : }
305 :
306 0 : state(stateCodes::NOTCONNECTED);
307 :
308 0 : return 0;
309 : }
310 :
311 0 : int trippLitePDU::appLogic()
312 : {
313 0 : if( state() == stateCodes::NOTCONNECTED )
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 0 : int rv = devConnect();
319 :
320 0 : if(rv == 0)
321 : {
322 0 : state(stateCodes::CONNECTED);
323 :
324 0 : if(!stateLogged())
325 : {
326 0 : std::string logs = "Connected to " + m_deviceAddr + ":" + m_devicePort;
327 0 : log<text_log>(logs);
328 0 : }
329 0 : lastrv = rv;
330 0 : lasterrno = errno;
331 : }
332 : else
333 : {
334 0 : if(!stateLogged())
335 : {
336 0 : log<text_log>({"Failed to connect to " + m_deviceAddr + ":" + m_devicePort}, logPrio::LOG_ERROR);
337 : }
338 0 : if( rv != lastrv )
339 : {
340 0 : log<software_error>( {__FILE__,__LINE__, 0, rv, tty::ttyErrorString(rv)} );
341 0 : lastrv = rv;
342 : }
343 0 : if( errno != lasterrno )
344 : {
345 0 : log<software_error>( {__FILE__,__LINE__, errno});
346 0 : lasterrno = errno;
347 : }
348 0 : return 0;
349 : }
350 : }
351 :
352 0 : if( state() == stateCodes::CONNECTED )
353 : {
354 0 : int rv = devLogin();
355 :
356 0 : if(rv == 0)
357 : {
358 0 : state(stateCodes::LOGGEDIN);
359 : }
360 : else
361 : {
362 0 : if(rv == TELNET_E_LOGINTIMEOUT)
363 : {
364 0 : state(stateCodes::NOTCONNECTED);
365 0 : log<text_log>("login timedout", logPrio::LOG_ERROR);
366 0 : return 0;
367 : }
368 :
369 0 : state(stateCodes::FAILURE);
370 0 : log<text_log>("login failure", logPrio::LOG_CRITICAL);
371 0 : return -1;
372 : }
373 : }
374 :
375 0 : if(state() == stateCodes::LOGGEDIN)
376 : {
377 0 : devPostLogin();
378 :
379 0 : state(stateCodes::READY);
380 : }
381 :
382 0 : if(state() == stateCodes::READY)
383 : {
384 0 : std::unique_lock<std::mutex> lock(m_indiMutex, std::try_to_lock);
385 :
386 0 : if( !lock.owns_lock())
387 : {
388 0 : return 0;
389 : }
390 :
391 0 : int rv = updateOutletStates();
392 :
393 0 : if(rv < 0) return log<software_error,-1>({__FILE__, __LINE__});
394 :
395 0 : updateAlarmsAndWarnings();
396 :
397 0 : return 0;
398 0 : }
399 :
400 0 : state(stateCodes::FAILURE);
401 0 : log<text_log>("appLogic fell through", logPrio::LOG_CRITICAL);
402 0 : return -1;
403 :
404 : }
405 :
406 0 : int trippLitePDU::appShutdown()
407 : {
408 : //don't bother
409 0 : return 0;
410 : }
411 :
412 0 : int trippLitePDU::updateOutletState( int outletNum )
413 : {
414 : static_cast<void>(outletNum);
415 :
416 0 : return updateOutletStates(); //We can't do just one.
417 : }
418 :
419 :
420 0 : int trippLitePDU::updateOutletStates()
421 : {
422 : int rv;
423 0 : std::string strRead;
424 :
425 0 : rv = devStatus(strRead);
426 :
427 0 : if(rv < 0 )
428 : {
429 0 : log<software_error>({__FILE__, __LINE__, "error getting device status"});
430 0 : state(stateCodes::NOTCONNECTED);
431 0 : return 0;
432 : }
433 :
434 0 : if(rv > 0)
435 : {
436 0 : return 0; //this means the re-read was successful, but we don't want to parse this time.
437 : }
438 :
439 0 : rv = parsePDUStatus( strRead);
440 :
441 0 : if(rv == 0)
442 : {
443 0 : updateIfChanged(m_indiP_status, "value", m_status);
444 :
445 0 : updateIfChanged(m_indiP_load, "frequency", m_frequency);
446 :
447 0 : updateIfChanged(m_indiP_load, "voltage", m_voltage);
448 :
449 0 : updateIfChanged(m_indiP_load, "current", m_current);
450 :
451 0 : dev::outletController<trippLitePDU>::updateINDI();
452 : }
453 : else
454 : {
455 0 : log<software_error>({__FILE__, __LINE__, 0, rv, "parse error"});
456 : }
457 :
458 0 : return 0;
459 0 : }
460 :
461 0 : int trippLitePDU::turnOutletOn( int outletNum )
462 : {
463 0 : 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 0 : int rv = m_simulator.turnOutletOn(outletNum);
475 :
476 : #endif
477 :
478 0 : if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
479 :
480 0 : return 0;
481 0 : }
482 :
483 0 : int trippLitePDU::turnOutletOff( int outletNum )
484 : {
485 0 : 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 0 : int rv = m_simulator.turnOutletOff(outletNum);
497 :
498 : #endif
499 :
500 0 : if(rv < 0) return log<software_error, -1>({__FILE__, __LINE__, 0, rv, "telnet error"});
501 :
502 0 : return 0;
503 0 : }
504 :
505 0 : int trippLitePDU::devConnect()
506 : {
507 : #ifndef XWC_SIM_MODE
508 :
509 : return m_telnetConn.connect(m_deviceAddr, m_devicePort);
510 :
511 : #else
512 :
513 0 : return m_simulator.connect(m_deviceAddr, m_devicePort);
514 :
515 : #endif
516 : }
517 :
518 0 : int trippLitePDU::devLogin()
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 0 : return m_simulator.login("localadmin", "localadmin");
534 :
535 : #endif
536 : }
537 :
538 0 : void trippLitePDU::devPostLogin()
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 : {
546 : m_telnetConn.writeRead("E\n", false, m_writeTimeout, m_readTimeout);
547 : m_telnetConn.m_prompt = "$> ";
548 : }
549 :
550 : #else
551 :
552 0 : m_simulator.postLogin();
553 :
554 : #endif
555 0 : }
556 :
557 0 : 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 :
565 : if(rv == TTY_E_TIMEOUTONREAD || rv == TTY_E_TIMEOUTONREADPOLL)
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 0 : return m_simulator.devStatus(strRead);
590 :
591 : #endif
592 : }
593 :
594 0 : int trippLitePDU::parsePDUStatus( std::string & strRead )
595 : {
596 0 : size_t curpos = 0;
597 :
598 0 : curpos = strRead.find_first_of("\r\n", curpos);
599 :
600 0 : std::string sstr;
601 :
602 0 : while(curpos < strRead.size())
603 : {
604 0 : size_t eol = strRead.find_first_of("\r\n", curpos);
605 :
606 0 : if(eol == std::string::npos) eol = strRead.size();
607 :
608 0 : if(eol == curpos)
609 : {
610 0 : curpos = eol + 1;
611 0 : continue;
612 : }
613 :
614 0 : sstr = strRead.substr(curpos, eol-curpos);
615 0 : curpos = eol + 1;
616 :
617 0 : if(sstr[0] == '-' || sstr[0] == '0' || sstr[0] == 'L' || sstr[0] == ' ' || sstr[0] == 'D' || sstr[0] == '$') continue;
618 :
619 0 : if(sstr[0] == 'I')
620 : {
621 0 : if(sstr[6] == 'V')
622 : {
623 0 : size_t begin = sstr.find(' ',6);
624 0 : if(begin == std::string::npos)
625 : {
626 0 : return -1;
627 : }
628 :
629 0 : begin = sstr.find_first_not_of(' ', begin);
630 0 : if(begin == std::string::npos)
631 : {
632 0 : return -2;
633 : }
634 :
635 0 : size_t end = sstr.find('V', begin);
636 0 : if(end == std::string::npos)
637 : {
638 0 : return -3;
639 : }
640 :
641 0 : float V = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
642 :
643 0 : m_voltage = V;
644 : }
645 :
646 0 : else if(sstr[6] == 'F')
647 : {
648 0 : size_t begin = sstr.find(' ',6);
649 0 : if(begin == std::string::npos)
650 : {
651 0 : return -4;
652 : }
653 :
654 0 : begin = sstr.find_first_not_of(' ', begin);
655 0 : if(begin == std::string::npos)
656 : {
657 0 : return -5;
658 : }
659 :
660 0 : size_t end = sstr.find('H', begin);
661 0 : if(end == std::string::npos)
662 : {
663 0 : return -6;
664 : }
665 :
666 0 : float F = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
667 :
668 0 : m_frequency = F;
669 : }
670 0 : else return -1;
671 : }
672 0 : else if(sstr[0] == 'O')
673 : {
674 0 : if(sstr[7] == 'C')
675 : {
676 0 : size_t begin = sstr.find(' ',7);
677 0 : if(begin == std::string::npos)
678 : {
679 0 : return -7;
680 : }
681 :
682 0 : begin = sstr.find_first_not_of(' ', begin);
683 0 : if(begin == std::string::npos)
684 : {
685 0 : return -8;
686 : }
687 :
688 0 : size_t end = sstr.find('A', begin);
689 0 : if(end == std::string::npos)
690 : {
691 0 : return -9;
692 : }
693 :
694 0 : float C = mx::ioutils::convertFromString<float>( sstr.substr(begin, end-begin) );
695 :
696 0 : m_current = C;
697 : }
698 0 : else if(sstr[8] == 'O')
699 : {
700 0 : std::vector<int> outletStates(m_outletStates.size(),OUTLET_STATE_OFF);
701 :
702 0 : size_t begin = sstr.find(' ',8);
703 0 : if(begin == std::string::npos)
704 : {
705 0 : return -10;
706 : }
707 :
708 0 : begin = sstr.find_first_not_of(' ', begin);
709 :
710 0 : if(begin == std::string::npos)
711 : {
712 0 : return -11;
713 : }
714 :
715 0 : while(begin < sstr.size())
716 : {
717 0 : size_t end = sstr.find(' ', begin);
718 0 : if(end == std::string::npos)
719 : {
720 0 : end = sstr.size();
721 : }
722 :
723 0 : int onum = atoi(sstr.substr(begin, end-begin).c_str());
724 :
725 0 : if(onum > 0 && onum < 9)
726 : {
727 0 : outletStates[onum-1] = OUTLET_STATE_ON; //this outlet is on.
728 : }
729 0 : begin = sstr.find_first_not_of(' ', end+1);
730 : }
731 :
732 0 : for(size_t i=0;i<m_outletStates.size();++i)
733 : {
734 0 : m_outletStates[i]=outletStates[i];
735 : }
736 0 : }
737 0 : else if( sstr[7] == 'V' || sstr[7] == 'F')
738 : {
739 0 : continue;
740 : }
741 : else
742 : {
743 0 : return -12;
744 : }
745 : }
746 : else
747 : {
748 0 : return -13;
749 : }
750 : }
751 :
752 0 : return 0;
753 0 : }
754 :
755 0 : void trippLitePDU::updateAlarmsAndWarnings()
756 : {
757 0 : if (m_frequency <= m_freqLowEmerg)
758 : {
759 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
760 0 : std::to_string(m_freqLowEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
761 : }
762 0 : else if (m_frequency >= m_freqHighEmerg)
763 : {
764 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
765 0 : std::to_string(m_freqHighEmerg) + " Hz.", logPrio::LOG_EMERGENCY);
766 : }
767 0 : else if (m_frequency <= m_freqLowAlert)
768 : {
769 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
770 0 : std::to_string(m_freqLowAlert) + " Hz.", logPrio::LOG_ALERT);
771 : }
772 0 : else if (m_frequency >= m_freqHighAlert)
773 : {
774 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
775 0 : std::to_string(m_freqHighAlert) + " Hz.", logPrio::LOG_ALERT);
776 : }
777 0 : else if(m_frequency <= m_freqLowWarn)
778 : {
779 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, below " +
780 0 : std::to_string(m_freqLowWarn) + " Hz.", logPrio::LOG_WARNING);
781 : }
782 0 : else if (m_frequency >= m_freqHighWarn)
783 : {
784 0 : log<text_log>("Frequency is " + std::to_string(m_frequency) + " Hz, above " +
785 0 : std::to_string(m_freqHighWarn) + " Hz.", logPrio::LOG_WARNING);
786 : }
787 :
788 0 : if (m_voltage <= m_voltLowEmerg)
789 : {
790 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
791 0 : std::to_string(m_voltLowEmerg) + " V.", logPrio::LOG_EMERGENCY);
792 : }
793 0 : else if (m_voltage >= m_voltHighEmerg)
794 : {
795 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
796 0 : std::to_string(m_voltHighEmerg) + " V.", logPrio::LOG_EMERGENCY);
797 : }
798 0 : else if (m_voltage <= m_voltLowAlert)
799 : {
800 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
801 0 : std::to_string(m_voltLowAlert) + " V.", logPrio::LOG_ALERT);
802 : }
803 0 : else if (m_voltage >= m_voltHighAlert)
804 : {
805 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
806 0 : std::to_string(m_voltHighAlert) + " V.", logPrio::LOG_ALERT);
807 : }
808 0 : else if(m_voltage <= m_voltLowWarn)
809 : {
810 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, below " +
811 0 : std::to_string(m_voltLowWarn) + " V.", logPrio::LOG_WARNING);
812 : }
813 0 : else if (m_voltage >= m_voltHighWarn)
814 : {
815 0 : log<text_log>("Voltage is " + std::to_string(m_voltage) + " V, above " +
816 0 : std::to_string(m_voltHighWarn) + " V.", logPrio::LOG_WARNING);
817 : }
818 :
819 0 : if (m_current >= m_currEmerg)
820 : {
821 0 : log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
822 0 : std::to_string(m_currEmerg) + " A.", logPrio::LOG_EMERGENCY);
823 : }
824 0 : else if (m_current >= m_currAlert)
825 : {
826 0 : log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
827 0 : std::to_string(m_currAlert) + " A.", logPrio::LOG_ALERT);
828 : }
829 0 : else if (m_current >= m_currWarn)
830 : {
831 0 : log<text_log>("Current is " + std::to_string(m_current) + " A, above " +
832 0 : std::to_string(m_currWarn) + " A.", logPrio::LOG_WARNING);
833 : }
834 0 : }
835 :
836 : } //namespace app
837 : } //namespace MagAOX
838 :
839 : #endif //trippLitePDU_hpp
|