API
 
Loading...
Searching...
No Matches
usbtempMon.hpp
Go to the documentation of this file.
1/** \file usbtempMon.hpp
2 * \brief The MagAO-X XXXXXX header file
3 *
4 * \ingroup usbtempMon_files
5 */
6
7#ifndef usbtempMon_hpp
8#define usbtempMon_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
14extern "C"
15{
16#include "usbtemp.h"
17}
18
19/** \defgroup usbtempMon
20 * \brief The XXXXXX application to do YYYYYYY
21 *
22 * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
23 *
24 * \ingroup apps
25 *
26 */
27
28/** \defgroup usbtempMon_files
29 * \ingroup usbtempMon
30 */
31
32namespace MagAOX
33{
34namespace app
35{
36
37/// The MagAO-X xxxxxxxx
38/**
39 * \ingroup usbtempMon
40 */
41class usbtempMon : public MagAOXApp<true>, public tty::usbDevice, public dev::telemeter<usbtempMon>
42{
43
44 //Give the test harness access.
45 friend class usbtempMon_test;
46
47 friend class dev::telemeter<usbtempMon>;
48
49protected:
50
51 /** \name Configurable Parameters
52 *@{
53 */
54
55 //here add parameters which will be config-able at runtime
56
57 float m_warnTemp {40};
58 float m_alertTemp {50};
59 float m_emergTemp {55};
60
61 ///@}
62
63
64 struct probe
65 {
66 std::string m_location;
67 std::string m_serial;
68 int m_fd {0};
69 std::string m_devName;
70
72
73 bool operator<(const probe& p) const
74 {
75 return m_location < p.m_location;
76 }
77 };
78
79 std::vector<probe> m_probes;
80
81
82 pcf::IndiProperty m_indiP_temps;
83
84public:
85 /// Default c'tor.
86 usbtempMon();
87
88 /// D'tor, declared and defined for noexcept.
91
92 virtual void setupConfig();
93
94 /// Implementation of loadConfig logic, separated for testing.
95 /** This is called by loadConfig().
96 */
97 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
98
99 virtual void loadConfig();
100
101 /// Startup function
102 /**
103 *
104 */
105 virtual int appStartup();
106
107 /// Implementation of the FSM for usbtempMon.
108 /**
109 * \returns 0 on no critical error
110 * \returns -1 on an error requiring shutdown
111 */
112 virtual int appLogic();
113
114 /// Shutdown the app.
115 /**
116 *
117 */
118 virtual int appShutdown();
119
120
121 int checkConnections();
122
123 /** \name Telemeter Interface
124 *
125 * @{
126 */
127 int checkRecordTimes();
128
129 int recordTelem( const telem_temps * );
130
131protected:
132 std::vector<float> m_lastTemps;
133
134 int recordTemps( bool force = false );
135
136};
137
138usbtempMon::usbtempMon() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
139{
140
141 return;
142}
143
145{
146 config.add("temp.warning", "", "temp.warning", argType::Required, "temp", "warning", false, "float", "Temperature at which to issue a warning. Default is 40.");
147 config.add("temp.alert", "", "temp.alert", argType::Required, "temp", "alert", false, "float", "Temperature at which to issue an alert. Default is 50.");
148 config.add("temp.emergency", "", "temp.emergency", argType::Required, "temp", "emergency", false, "float", "Temperature at which to issue an emergency. Default is 55.");
149
150
151 config.add("usb.idVendor", "", "usb.idVendor", argType::Required, "usb", "idVendor", false, "string", "USB vendor id, 4 digits");
152 config.add("usb.idProduct", "", "usb.idProduct", argType::Required, "usb", "idProduct", false, "string", "USB product id, 4 digits");
153
155}
156
157int usbtempMon::loadConfigImpl( mx::app::appConfigurator & _config )
158{
159
160 _config(m_warnTemp, "temp.warning");
161 _config(m_alertTemp, "temp.alert");
162 _config(m_emergTemp, "temp.emergency");
163
164 m_idVendor = "067b";
165 _config(m_idVendor, "usb.idVendor");
166 m_idProduct = "2303";
167 _config(m_idProduct, "usb.idProduct");
168
169
170 std::vector<std::string> sections;
171
172 _config.unusedSections(sections);
173
174 if( sections.size() == 0 )
175 {
176 log<text_log>("No temperature probes found in config.", logPrio::LOG_CRITICAL);
177 m_shutdown = 1;
178 return -1;
179 }
180
181 for(size_t i=0; i< sections.size(); ++i)
182 {
183 if(config.isSetUnused(mx::app::iniFile::makeKey(sections[i], "serial" )))
184 {
185 m_probes.emplace_back();
186 config.configUnused(m_probes.back().m_serial, mx::app::iniFile::makeKey(sections[i], "serial" ));
187 m_probes.back().m_serial = mx::ioutils::toLower(m_probes.back().m_serial);
188
189 m_probes.back().m_location = sections[i];
190 config.configUnused(m_probes.back().m_location, mx::app::iniFile::makeKey(sections[i], "location" ));
191 }
192 }
193
194 std::sort( m_probes.begin(), m_probes.end());
195
197
198 return 0;
199}
200
202{
203 loadConfigImpl(config);
204}
205
207{
208 createROIndiNumber( m_indiP_temps, "temperature", "Temperature [C]");
209 for(size_t n =0; n < m_probes.size(); ++n)
210 {
211 indi::addNumberElement<double>( m_indiP_temps, m_probes[n].m_location, -20., 120., 0, "%0.2f");
212 m_indiP_temps[m_probes[n].m_location] = -999;
213 }
215
216
218 {
219 return log<software_error,-1>({__FILE__,__LINE__});
220 }
221
222 return checkConnections();
223}
224
226{
227 bool checkConn = false;
228 for(size_t n =0; n < m_probes.size(); ++n)
229 {
230 if(m_probes[n].m_fd > 0)
231 {
232 float temperature = -1e37;
233 if (DS18B20_acquire(m_probes[n].m_fd, &temperature) < 0)
234 {
235 log<software_error>({__FILE__, __LINE__, "Did not get temp from " + m_probes[n].m_location + ". Error: " + DS18B20_errmsg()});
236 DS18B20_close(m_probes[n].m_fd);
237 m_probes[n].m_fd = 0;
238 checkConn = true;
239 continue;
240 }
241
242 m_probes[n].m_temperature = temperature;
243 updateIfChanged(m_indiP_temps, m_probes[n].m_location, temperature);
244
245 if(temperature >= m_warnTemp)
246 {
247 log<text_log>(m_probes[n].m_location + " temp = " + std::to_string(temperature), logPrio::LOG_WARNING);
248 }
249 else if(temperature >= m_alertTemp)
250 {
251 log<text_log>(m_probes[n].m_location + " temp = " + std::to_string(temperature), logPrio::LOG_ALERT);
252 }
253 else if(temperature >= m_emergTemp)
254 {
255 log<text_log>(m_probes[n].m_location + " temp = " + std::to_string(temperature), logPrio::LOG_EMERGENCY);
256 }
257
258 recordTemps(); //log it in telemeter
259
260
261 if (DS18B20_measure(m_probes[n].m_fd) < 0)
262 {
263 log<software_error>({__FILE__, __LINE__, "Error from " + m_probes[n].m_location + ". Error: " + DS18B20_errmsg()});
264 DS18B20_close(m_probes[n].m_fd);
265 m_probes[n].m_fd = 0;
266 updateIfChanged(m_indiP_temps, m_probes[n].m_location, -999);
267 checkConn = true;
268 continue;
269 }
270 }
271 else
272 {
273 updateIfChanged(m_indiP_temps, m_probes[n].m_location, -999);
274 checkConn = true;
275 }
276
277
278 }
279
280 if(checkConn)
281 {
283 }
284
286 {
288 }
289
291 {
293 return 0;
294 }
295
296 return 0;
297}
298
300{
301 return 0;
302}
303
305{
306 std::vector<std::string> devNames;
307
309
310 int nconn = 0;
311 for(size_t i=0; i< devNames.size(); ++i)
312 {
313 elevatedPrivileges ep(this);
314
315 int fd = DS18B20_open(devNames[i].c_str());
316 ep.restore();
317
318 if (!is_fd_valid(fd))
319 {
322 continue;
323 }
324
325
326
327 unsigned char rom[DS18X20_ROM_SIZE];
328 char romstr[2*DS18X20_ROM_SIZE+1];
329 if (DS18B20_rom(fd, rom) < 0)
330 {
333 continue;
334 }
335
336 for (size_t i = 0; i < DS18X20_ROM_SIZE; i++)
337 {
338 snprintf(romstr + 2*i, 3, "%02x", rom[i]);
339 }
340
341 for(size_t j=0;j< m_probes.size();++j)
342 {
343 if( m_probes[j].m_serial == romstr)
344 {
345 if(m_probes[j].m_fd > 0 ) //Check if we're already connected to this one
346 {
347 if( m_probes[j].m_devName == devNames[i]) //This means we are still good
348 {
349 ++nconn;
351 fd = 0;
352 break;
353 }
354
355 //If here, something changed, and so we close the existing fd and reconnect.
356 DS18B20_close(m_probes[j].m_fd);
357 }
358
359 m_probes[j].m_fd = fd;
360 fd = 0;
361 m_probes[j].m_devName=devNames[i];
362
363 log<text_log>("Found " + m_probes[j].m_location + " [" + m_probes[j].m_serial + "] as " + m_probes[j].m_devName);
364
365 ++nconn;
366 if (DS18B20_measure(m_probes[j].m_fd) < 0)
367 {
368 log<software_error>({__FILE__, __LINE__, "Error from " + m_probes[j].m_location + ". Error: " + DS18B20_errmsg()});
369
370 DS18B20_close(m_probes[j].m_fd);
371 m_probes[j].m_fd = 0;
372 }
373 break;
374 }
375 }
376
377 if(fd != 0)
378 {
379 log<text_log>("no match for " + devNames[i]);
381 }
382 }
383
386
387 return 0;
388}
389
394
396{
397 return recordTemps(true);
398}
399
400inline
402{
403 if(m_lastTemps.size() != m_probes.size())
404 {
405 m_lastTemps.resize(m_probes.size());
406 for(size_t n=0; n<m_lastTemps.size(); ++n) m_lastTemps[n] = -1e30;
407 }
408
409 bool log = false;
410 std::vector<float> temps;
411 temps.resize(m_probes.size());
412 for(size_t n=0; n<temps.size(); ++n)
413 {
414 temps[n] = m_probes[n].m_temperature;
415 if(temps[n] != m_lastTemps[n]) log = true;
416 }
417
418 if(force || log)
419 {
421 for(size_t n=0; n<m_lastTemps.size(); ++n) m_lastTemps[n] = temps[n];
422 }
423
424 return 0;
425
426}
427
428} //namespace app
429} //namespace MagAOX
430
431#endif //usbtempMon_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 m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
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.
The MagAO-X xxxxxxxx.
pcf::IndiProperty m_indiP_temps
virtual int appStartup()
Startup function.
virtual int appShutdown()
Shutdown the app.
virtual void loadConfig()
~usbtempMon() noexcept
D'tor, declared and defined for noexcept.
std::vector< probe > m_probes
friend class usbtempMon_test
std::vector< float > m_lastTemps
int recordTelem(const telem_temps *)
virtual int appLogic()
Implementation of the FSM for usbtempMon.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int recordTemps(bool force=false)
virtual void setupConfig()
usbtempMon()
Default c'tor.
@ OPERATING
The device is operating, other than homing.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
int ttyUSBDevNames(std::vector< std::string > &devNames, const std::string &vendor, const std::string &product)
Get the ttyUSB device name for a set of devices specified by their vendor and product ids.
Definition ttyUSB.cpp:137
Definition dm.hpp:24
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_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.
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.
bool operator<(const probe &p) const
Software ERR log entry.
Log entry recording electronics rack temperature.
A USB device as a TTY device.
Definition usbDevice.hpp:33
std::string m_idProduct
The product id 4-digit code.
Definition usbDevice.hpp:35
std::string m_serial
The serial number.
Definition usbDevice.hpp:36
std::string m_idVendor
The vendor id 4-digit code.
Definition usbDevice.hpp:34
int DS18B20_acquire(HANDLE fd, float *temperature)
Definition usbtemp.c:172
int DS18B20_measure(HANDLE fd)
Definition usbtemp.c:115
HANDLE DS18B20_open(const char *serial_port)
Definition usbtemp.c:220
void DS18B20_close(HANDLE fd)
Definition usbtemp.c:225
int is_fd_valid(HANDLE fd)
Definition usbtemp.c:25
char * DS18B20_errmsg(void)
Definition usbtemp.c:68
int DS18B20_rom(HANDLE fd, unsigned char *rom)
Definition usbtemp.c:194
#define DS18X20_ROM_SIZE
Definition usbtemp.h:13