API
 
Loading...
Searching...
No Matches
rhusbMon.hpp
Go to the documentation of this file.
1/** \file rhusbMon.hpp
2 * \brief The MagAO-X RH USB monitor
3 *
4 * \ingroup rhusbMon_files
5 */
6
7#ifndef rhusbMon_hpp
8#define rhusbMon_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#include "rhusbMonParsers.hpp"
15
16/** \defgroup rhusbMon
17 * \brief Application to monitor an Omega RH USB probe.
18 *
19 * <a href="../handbook/operating/software/apps/rhusbMon.html">Application Documentation</a>
20 *
21 * \ingroup apps
22 *
23 */
24
25/** \defgroup rhusbMon_files
26 * \ingroup rhusbMon
27 */
28
29namespace MagAOX
30{
31namespace app
32{
33
34/// The MagAO-X RH-USB monitoring class
35/** Interacts with the Omega RH-USB probe used for DM chamber humidity monitoring.
36 *
37 * \todo need a test mode (compile-time) which adds a way (INDI?) to initiate testing of parameter limits.
38 *
39 * \ingroup rhusbMon
40 */
41class rhusbMon : public MagAOXApp<true>, public tty::usbDevice, public dev::ioDevice, public dev::telemeter<rhusbMon>
42{
43
44 //Give the test harness access.
45 friend class rhusbMon_test;
46
47 //Let telemeter work.
48 friend class dev::telemeter<rhusbMon>;
49
50protected:
51
52 /** \name Configurable Parameters
53 *@{
54 */
55 float m_warnTemp {30}; ///< This is abnormally high if the system is working, but still safe.
56 float m_alertTemp {35}; ///< This is the actual limit, shut down should occur.
57 float m_emergTemp {40}; ///< Must shutdown immediately.
58
59 float m_warnHumid {18}; ///< This is abnormally high if the system is working, but still safe.
60 float m_alertHumid {20}; ///< This is the actual limit, shut down should occur.
61 float m_emergHumid {22}; ///< Must shutdown immediately.
62
63 ///@}
64
65 float m_temp {-999};
66 float m_rh {-999};
67
68 pcf::IndiProperty m_indiP_temp;
69 pcf::IndiProperty m_indiP_rh;
70
71
72public:
73 /// Default c'tor.
74 rhusbMon();
75
76 /// D'tor, declared and defined for noexcept.
79
80 virtual void setupConfig();
81
82 /// Implementation of loadConfig logic, separated for testing.
83 /** This is called by loadConfig().
84 */
85 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
86
87 virtual void loadConfig();
88
89 /// Startup function
90 /**
91 *
92 */
93 virtual int appStartup();
94
95 /// Implementation of the FSM for rhusbMon.
96 /**
97 * \returns 0 on no critical error
98 * \returns -1 on an error requiring shutdown
99 */
100 virtual int appLogic();
101
102 /// Shutdown the app.
103 /**
104 *
105 */
106 virtual int appShutdown();
107
108 /// Connect to the probe
109 /** Search for the USB device in udev and attempt ot open it.
110 * The result is reported via the FSM state (NODEVICE, NOTCONNECTED, CONNECTED).
111 *
112 * \returns -1 on an error attempting to read udev
113 * \returns 0 if device not found, or connection does not work, or if connected.
114 */
115 int connect();
116
117 /// Read current values from the RH-USB probe
118 /** Issues the 'C' and 'H' commands to get temperature and humidity.
119 *
120 * \returns -1 on error writing or reading, or on a parsing error
121 *
122 * \see \parseC( float &, const std::string)
123 * \see \parseH( float &, const std::string)
124 */
125 int readProbe();
126
127 /** \name Telemeter Interface
128 *
129 * @{
130 */
131 int checkRecordTimes();
132
133 int recordTelem( const telem_rhusb * );
134
135protected:
136
137 int recordRH( bool force = false );
138
139 ///@}
140
141};
142
143rhusbMon::rhusbMon() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
144{
147
148 return;
149}
150
152{
153 config.add("temp.warning", "", "temp.warning", argType::Required, "temp", "warning", false, "float", "Temperature at which to issue a warning. Default is 30.");
154 config.add("temp.alert", "", "temp.alert", argType::Required, "temp", "alert", false, "float", "Temperature at which to issue an alert. Default is 35.");
155 config.add("temp.emergency", "", "temp.emergency", argType::Required, "temp", "emergency", false, "float", "Temperature at which to issue an emergency. Default is 40.");
156
157 config.add("humid.warning", "", "humid.warning", argType::Required, "humid", "warning", false, "float", "Humidity at which to issue a warning. Default is 18.");
158 config.add("humid.alert", "", "humid.alert", argType::Required, "humid", "alert", false, "float", "Humidity at which to issue an alert. Default is 20.");
159 config.add("humid.emergency", "", "humid.emergency", argType::Required, "humid", "emergency", false, "float", "Humidity at which to issue an emergency. Default is 22.");
160
163
165}
166
167int rhusbMon::loadConfigImpl( mx::app::appConfigurator & _config )
168{
169
170 _config(m_warnTemp, "temp.warning");
171 _config(m_alertTemp, "temp.alert");
172 _config(m_emergTemp, "temp.emergency");
173
174 _config(m_warnHumid, "humid.warning");
175 _config(m_alertHumid, "humid.alert");
176 _config(m_emergHumid, "humid.emergency");
177
180
182
183 return 0;
184}
185
187{
188 loadConfigImpl(config);
189}
190
192{
193 createROIndiNumber( m_indiP_temp, "temperature", "Temperature [C]");
194 indi::addNumberElement<float>( m_indiP_temp, "current", -20., 120., 0, "%0.1f");
195 m_indiP_temp["current"] = -999;
197
198 createROIndiNumber( m_indiP_rh, "humidity", "Relative Humidity [%]");
199 indi::addNumberElement<float>( m_indiP_rh, "current", 0., 100., 0, "%0.1f");
200 m_indiP_rh["current"] = -999;
202
203
205 {
206 return log<software_error,-1>({__FILE__,__LINE__});
207 }
208
209 return connect();
210}
211
212
213
215{
217 {
218 int rv = connect();
219 if(rv < 0) return log<software_error,-1>({__FILE__, __LINE__});
220 }
221
223 {
224 int rv = readProbe();
225 if(rv == 0)
226 {
228 }
229 else
230 {
233 }
234 }
235
236 pcf::IndiProperty::PropertyStateType rhState = pcf::IndiProperty::Ok;
237 //Check warning and alert values
238 if(m_rh > m_emergHumid)
239 {
240 log<text_log>("RH > " + std::to_string(m_emergHumid) + "% : " + std::to_string(m_rh) + "%! Shutdown immediately!", logPrio::LOG_EMERGENCY);
241 rhState = pcf::IndiProperty::Alert;
242 }
243 else if(m_rh > m_alertHumid)
244 {
245 log<text_log>("RH > " + std::to_string(m_alertHumid) + "% : " + std::to_string(m_rh) + "%. Fix or shutdown.", logPrio::LOG_ALERT);
246 rhState = pcf::IndiProperty::Alert;
247 }
248 else if(m_rh > m_warnHumid)
249 {
250 log<text_log>("RH > " + std::to_string(m_warnHumid) + "% : " + std::to_string(m_rh) + "%.", logPrio::LOG_WARNING);
251 rhState = pcf::IndiProperty::Alert;
252 }
253
254 pcf::IndiProperty::PropertyStateType tState = pcf::IndiProperty::Ok;
255 //Check warning and alert values
256 if(m_temp > m_emergTemp)
257 {
258 log<text_log>("Temp > " + std::to_string(m_emergTemp) + "C : " + std::to_string(m_temp) + "C! Shutdown immediately!", logPrio::LOG_EMERGENCY);
259 tState = pcf::IndiProperty::Alert;
260 }
261 else if(m_temp > m_alertTemp)
262 {
263 log<text_log>("Temp > " + std::to_string(m_alertTemp) + "C : " + std::to_string(m_temp) + "C. Fix or shutdown.", logPrio::LOG_ALERT);
264 tState = pcf::IndiProperty::Alert;
265 }
266 else if(m_temp > m_warnTemp)
267 {
268 log<text_log>("Temp > " + std::to_string(m_warnTemp) + "C : " + std::to_string(m_temp) + "C.", logPrio::LOG_WARNING);
269 tState = pcf::IndiProperty::Alert;
270 }
271
272 //Scope for mutex
273 {
274 std::unique_lock<std::mutex> lock(m_indiMutex);
276
277 m_indiP_rh["current"].set<float>(-999); //Force the update to get a new timestamp
278 updateIfChanged(m_indiP_rh, "current", m_rh, rhState); ///\todo updateIfChanged should have a force flag
279 }
280
282 {
284 }
285
286 return 0;
287}
288
290{
291 return 0;
292}
293
295{
297 if(rv < 0 && rv != TTY_E_DEVNOTFOUND && rv != TTY_E_NODEVNAMES)
298 {
299 //There is no device reason for this to error. Something is wrong.
302 }
303
305 {
307
308 if(!stateLogged())
309 {
310 std::stringstream logs;
311 logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " not found in udev";
312 log<text_log>(logs.str());
313 }
314 return 0;
315 }
316 else
317 {
319 if(!stateLogged())
320 {
321 std::stringstream logs;
322 logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " found in udev as " << m_deviceName;
323 log<text_log>(logs.str());
324 }
325
326 //scope for elevated priv
327 {
328 elevatedPrivileges elPriv(this);
330 }
331
332 if(rv == TTY_E_NOERROR)
333 {
335 if(!stateLogged())
336 {
337 std::stringstream logs;
338 logs << "Connected to " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " @ " << m_deviceName;
339 log<text_log>(logs.str());
340 }
341 }
342 else
343 {
344 //There is no power or other reason this should happen. It means something is wrong and needs to be corrected.
346 return log<software_critical, -1>({__FILE__,__LINE__, errno, rv, "Error opening connection: " + tty::ttyErrorString(rv)});
347 }
348 }
349
350 return 0;
351}
352
354{
355 std::string strRead;
356
358 if(rv != TTY_E_NOERROR)
359 {
360 return log<software_error,-1>({__FILE__, __LINE__, 0, rv, "Error reading temp: " + tty::ttyErrorString(rv)});
361 }
362
364 if(rv != 0)
365 {
366 if( rv == -1 )
367 {
368 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing temp, no EOT"});
369 }
370 else if (rv == -2 )
371 {
372 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing temp, no value"});
373 }
374 else if (rv == -3)
375 {
376 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing temp, does not begin with digit"});
377 }
378 else
379 {
380 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing temp."});
381 }
382 }
383
384 std::cout << m_temp << "\n";
385
387 if(rv != TTY_E_NOERROR)
388 {
389 return log<software_error,-1>({__FILE__, __LINE__, 0, rv, "Error reading RH: " + tty::ttyErrorString(rv)});
390 }
391
393 if(rv != 0)
394 {
395 if( rv == -1 )
396 {
397 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing humid, no EOT"});
398 }
399 else if (rv == -2 )
400 {
401 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing humid, no value"});
402 }
403 else if (rv == -3)
404 {
405 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing temp, does not begin with digit"});
406 }
407 else
408 {
409 return log<software_error, -1>({__FILE__, __LINE__, "Error parsing humid."});
410 }
411 }
412
413 std::cout << m_rh << "\n";
414
415 return 0;
416}
417
422
424{
425 return recordRH(true);
426}
427
428inline
429int rhusbMon::recordRH(bool force)
430{
431 static float lastTemp = -99;
432 static float lastRH = -99;
433
434 if(force || m_temp != lastTemp || m_rh != lastRH)
435 {
437 }
438
440 lastRH = m_rh;
441
442 return 0;
443
444}
445
446} //namespace app
447} //namespace MagAOX
448
449#endif //rhusbMon_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
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.
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.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
The MagAO-X RH-USB monitoring class.
Definition rhusbMon.hpp:42
float m_warnTemp
This is abnormally high if the system is working, but still safe.
Definition rhusbMon.hpp:55
virtual int appLogic()
Implementation of the FSM for rhusbMon.
Definition rhusbMon.hpp:214
rhusbMon()
Default c'tor.
Definition rhusbMon.hpp:143
int recordRH(bool force=false)
Definition rhusbMon.hpp:429
float m_emergTemp
Must shutdown immediately.
Definition rhusbMon.hpp:57
virtual int appStartup()
Startup function.
Definition rhusbMon.hpp:191
virtual void loadConfig()
Definition rhusbMon.hpp:186
virtual int appShutdown()
Shutdown the app.
Definition rhusbMon.hpp:289
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition rhusbMon.hpp:167
int recordTelem(const telem_rhusb *)
Definition rhusbMon.hpp:423
int readProbe()
Read current values from the RH-USB probe.
Definition rhusbMon.hpp:353
friend class rhusbMon_test
Definition rhusbMon.hpp:45
float m_alertTemp
This is the actual limit, shut down should occur.
Definition rhusbMon.hpp:56
pcf::IndiProperty m_indiP_temp
Definition rhusbMon.hpp:68
pcf::IndiProperty m_indiP_rh
Definition rhusbMon.hpp:69
int connect()
Connect to the probe.
Definition rhusbMon.hpp:294
float m_warnHumid
This is abnormally high if the system is working, but still safe.
Definition rhusbMon.hpp:59
virtual void setupConfig()
Definition rhusbMon.hpp:151
~rhusbMon() noexcept
D'tor, declared and defined for noexcept.
Definition rhusbMon.hpp:77
float m_emergHumid
Must shutdown immediately.
Definition rhusbMon.hpp:61
float m_alertHumid
This is the actual limit, shut down should occur.
Definition rhusbMon.hpp:60
@ OPERATING
The device is operating, other than homing.
@ NODEVICE
No device exists for the application to control.
@ FAILURE
The application has failed, should be used when m_shutdown is set for an error.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
int ttyWriteRead(std::string &strRead, const std::string &strWrite, const std::string &eot, bool swallowEcho, int fd, int timeoutWrite, int timeoutRead)
Write to a tty on an open file descriptor, then get the result.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
Definition ttyErrors.cpp:15
int parseH(float &humid, const std::string &str)
Parse the RH probe H humidity command.
int parseC(float &temp, const std::string &str)
Parse the RH probe C temp command.
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
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.
Parsers for the MagAO-X RH USB monitor.
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 device base class which saves telemetry.
Definition telemeter.hpp:69
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
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.
int getDeviceName()
Get the device name from udev using the vendor, product, and serial number.
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
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
#define TTY_E_NOERROR
Definition ttyErrors.hpp:15