Line data Source code
1 : /** \file koolanceCtrl.hpp
2 : * \brief The MagAO-X Koolance Controller header file
3 : *
4 : * \ingroup koolanceCtrl_files
5 : */
6 :
7 : #ifndef koolanceCtrl_hpp
8 : #define koolanceCtrl_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 : /** \defgroup koolanceCtrl
15 : * \brief The MagAO-X application to monitor and control a Koolance cooler
16 : *
17 : * <a href="../handbook/operating/software/apps/koolanceCtrl.html">Application Documentation</a>
18 : *
19 : * \ingroup apps
20 : *
21 : */
22 :
23 : /** \defgroup koolanceCtrl_files
24 : * \ingroup koolanceCtrl
25 : */
26 :
27 : namespace MagAOX
28 : {
29 : namespace app
30 : {
31 :
32 : /// The MagAO-X Koolance Controller
33 : /** This application will monitor a Koolance v1 or v2 protocol controller. If v2, will also allow
34 : * changing of pump and fan settings via INDI.
35 : *
36 : * \ingroup koolanceCtrl
37 : */
38 : class koolanceCtrl : public MagAOXApp<true>, public tty::usbDevice, public dev::telemeter<koolanceCtrl>
39 : {
40 :
41 : //Give the test harness access.
42 : friend class koolanceCtrl_test;
43 :
44 : friend class dev::telemeter<koolanceCtrl>;
45 : protected:
46 :
47 : /** \name Configurable Parameters
48 : *@{
49 : */
50 :
51 : //here add parameters which will be config-able at runtime
52 :
53 : ///@}
54 :
55 : size_t m_protocolChars {0}; ///< Will be set to 43 if protocol 1, and set to 51 if protocol 2.
56 :
57 : bool m_indiSetup {false}; ///< Whether or not INDI has been set up after initial protocol determination.
58 :
59 : float m_liqTemp {0}; ///< The liquid temperature
60 : float m_flowRate {0}; ///< The flow rate
61 : int m_pumpLvl {0}; ///< The pump power level, 1-10
62 : int m_pumpRPM {0}; ///< The pump RPM
63 : int m_fanRPM {0}; ///< The fan RPM
64 : int m_fanLvl {0}; ///< The fan power level, 0-100
65 :
66 :
67 :
68 : public:
69 : /// Default c'tor.
70 : koolanceCtrl();
71 :
72 : /// D'tor, declared and defined for noexcept.
73 0 : ~koolanceCtrl() noexcept
74 0 : {}
75 :
76 : virtual void setupConfig();
77 :
78 : /// Implementation of loadConfig logic, separated for testing.
79 : /** This is called by loadConfig().
80 : */
81 : int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
82 :
83 : virtual void loadConfig();
84 :
85 : /// Startup function
86 : /**
87 : *
88 : */
89 : virtual int appStartup();
90 :
91 : /// Implementation of the FSM for koolanceCtrl.
92 : /**
93 : * \returns 0 on no critical error
94 : * \returns -1 on an error requiring shutdown
95 : */
96 : virtual int appLogic();
97 :
98 : /// Shutdown the app.
99 : /**
100 : *
101 : */
102 : virtual int appShutdown();
103 :
104 : /// Initial connection to controller
105 : /** Determine protocol in use based on number of characters in response
106 : * and sets up INDI appropriately.
107 : *
108 : * Calls to this function should be mutexed.
109 : *
110 : * \returns 0 on success
111 : * \returns -1 on an error
112 : */
113 : int initialConnect();
114 :
115 : /// Get status from controller and updated INDI.
116 : /**
117 : *
118 : * Calls to this function should be mutexed.
119 : *
120 : * \returns 0 on success
121 : * \returns -1 on an error
122 : */
123 : int getStatus();
124 :
125 : /// Set the pump level
126 : /**
127 : * Calls to this function should be mutexed.
128 : *
129 : * \returns 0 on success
130 : * \returns -1 on an error
131 : */
132 : int setPumpLvl(int lvl /**< [in] the new level */);
133 :
134 : /// Set the fan level
135 : /**
136 : * Calls to this function should be mutexed.
137 : *
138 : * \returns 0 on success
139 : * \returns -1 on an error
140 : */
141 : int setFanLvl(int lvl /**< [in] the new level */);
142 :
143 : /** \name INDI
144 : *
145 : *@{
146 : */
147 : protected:
148 : //declare our properties
149 : pcf::IndiProperty m_indiP_status;
150 : pcf::IndiProperty m_indiP_pumplvl;
151 : pcf::IndiProperty m_indiP_fanlvl;
152 :
153 : public:
154 0 : INDI_NEWCALLBACK_DECL(koolanceCtrl, m_indiP_pumplvl);
155 0 : INDI_NEWCALLBACK_DECL(koolanceCtrl, m_indiP_fanlvl);
156 :
157 : ///@}
158 :
159 : /** \name Telemeter Interface
160 : *
161 : * @{
162 : */
163 : int checkRecordTimes();
164 :
165 : int recordTelem( const telem_cooler * );
166 :
167 : int recordCooler(bool force = false);
168 :
169 : ///@}
170 :
171 :
172 : };
173 :
174 0 : koolanceCtrl::koolanceCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
175 : {
176 0 : return;
177 0 : }
178 :
179 0 : void koolanceCtrl::setupConfig()
180 : {
181 0 : tty::usbDevice::setupConfig(config);
182 :
183 0 : dev::telemeter<koolanceCtrl>::setupConfig(config);
184 :
185 0 : }
186 :
187 0 : int koolanceCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
188 : {
189 0 : this->m_baudRate = B9600; //default for a Koolance controller. Will be overridden by any config setting.
190 :
191 0 : int rv = tty::usbDevice::loadConfig(_config);
192 :
193 0 : if(rv != 0 && rv != TTY_E_NODEVNAMES && rv != TTY_E_DEVNOTFOUND) //Ignore error if not plugged in
194 : {
195 0 : log<software_error>( {__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
196 : }
197 :
198 0 : return 0;
199 : }
200 :
201 0 : void koolanceCtrl::loadConfig()
202 : {
203 0 : loadConfigImpl(config);
204 :
205 0 : dev::telemeter<koolanceCtrl>::loadConfig(config);
206 0 : }
207 :
208 0 : int koolanceCtrl::appStartup()
209 : {
210 0 : if( state() == stateCodes::UNINITIALIZED )
211 : {
212 0 : log<text_log>( "In appStartup but in state UNINITIALIZED.", logPrio::LOG_CRITICAL );
213 0 : return -1;
214 : }
215 :
216 : // set up the INDI properties
217 0 : REG_INDI_NEWPROP_NOCB(m_indiP_status, "status", pcf::IndiProperty::Number);
218 0 : m_indiP_status.add(pcf::IndiElement("liquid_temp"));
219 0 : m_indiP_status.add(pcf::IndiElement("flow_rate"));
220 0 : m_indiP_status.add(pcf::IndiElement("pump_rpm"));
221 0 : m_indiP_status.add(pcf::IndiElement("fan_rpm"));
222 :
223 0 : if(dev::telemeter<koolanceCtrl>::appStartup() < 0)
224 : {
225 0 : return log<software_error,-1>({__FILE__,__LINE__});
226 : }
227 :
228 0 : state(stateCodes::NODEVICE);
229 0 : return 0;
230 : }
231 :
232 0 : int koolanceCtrl::appLogic()
233 : {
234 :
235 0 : if( state() == stateCodes::NODEVICE )
236 : {
237 0 : int rv = tty::usbDevice::getDeviceName();
238 0 : if(rv < 0 && rv != TTY_E_DEVNOTFOUND && rv != TTY_E_NODEVNAMES)
239 : {
240 0 : state(stateCodes::FAILURE);
241 0 : if(!stateLogged())
242 : {
243 0 : log<software_critical>({__FILE__, __LINE__, rv, tty::ttyErrorString(rv)});
244 : }
245 0 : return -1;
246 : }
247 :
248 0 : if(rv == TTY_E_DEVNOTFOUND || rv == TTY_E_NODEVNAMES)
249 : {
250 0 : state(stateCodes::NODEVICE);
251 :
252 0 : if(!stateLogged())
253 : {
254 0 : std::stringstream logs;
255 0 : logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " not found in udev";
256 0 : log<text_log>(logs.str());
257 0 : }
258 0 : return 0;
259 : }
260 : else
261 : {
262 0 : std::stringstream logs;
263 0 : logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " found in udev as " << m_deviceName;
264 0 : log<text_log>(logs.str());
265 :
266 0 : state(stateCodes::NOTCONNECTED);
267 0 : }
268 : }
269 :
270 0 : if( state() == stateCodes::NOTCONNECTED )
271 : {
272 0 : int rv = 0;
273 : {
274 0 : elevatedPrivileges ep(this);
275 0 : rv = connect();
276 0 : }
277 :
278 0 : if(rv < 0)
279 : {
280 0 : int nrv = tty::usbDevice::getDeviceName();
281 0 : if(nrv < 0 && nrv != TTY_E_DEVNOTFOUND && nrv != TTY_E_NODEVNAMES)
282 : {
283 0 : state(stateCodes::FAILURE);
284 0 : if(!stateLogged()) log<software_critical>({__FILE__, __LINE__, nrv, tty::ttyErrorString(nrv)});
285 0 : return -1;
286 : }
287 :
288 0 : if(nrv == TTY_E_DEVNOTFOUND || nrv == TTY_E_NODEVNAMES)
289 : {
290 0 : state(stateCodes::NODEVICE);
291 :
292 0 : if(!stateLogged())
293 : {
294 0 : std::stringstream logs;
295 0 : logs << "USB Device " << m_idVendor << ":" << m_idProduct << ":" << m_serial << " no longer found in udev";
296 0 : log<text_log>(logs.str());
297 0 : }
298 0 : return 0;
299 : }
300 :
301 : //if connect failed, and there is a device, then we have some other problem.
302 0 : sleep(1); //wait to see if power state updates
303 0 : if(m_powerState == 0) return 0;
304 :
305 : //Ok we can't figure this out, die.
306 0 : state(stateCodes::FAILURE);
307 0 : if(!stateLogged()) log<software_error>({__FILE__,__LINE__,rv, tty::ttyErrorString(rv)});
308 0 : return -1;
309 :
310 : }
311 : else
312 : {
313 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
314 0 : if(initialConnect () == 0)
315 : {
316 0 : state(stateCodes::CONNECTED);
317 : }
318 : else
319 : {
320 0 : if(!stateLogged())
321 : {
322 0 : log<text_log>("no response from device");
323 : }
324 0 : return 0;
325 : }
326 0 : }
327 :
328 0 : if(state() == stateCodes::CONNECTED)
329 : {
330 0 : std::stringstream logs;
331 0 : logs << "Connected to koolance system on " << m_deviceName;
332 0 : log<text_log>(logs.str());
333 0 : state(stateCodes::READY);
334 0 : return 0;
335 0 : }
336 :
337 : }
338 :
339 0 : if( state() == stateCodes::READY )
340 : {
341 : { //mutex scope
342 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
343 0 : if(getStatus() < 0)
344 : {
345 0 : log<software_error>({__FILE__,__LINE__});
346 : }
347 0 : }
348 :
349 0 : if(telemeter<koolanceCtrl>::appLogic() < 0)
350 : {
351 0 : log<software_error>({__FILE__, __LINE__});
352 0 : return 0;
353 : }
354 0 : return 0;
355 : }
356 :
357 0 : return 0;
358 : }
359 :
360 0 : int koolanceCtrl::appShutdown()
361 : {
362 0 : dev::telemeter<koolanceCtrl>::appShutdown();
363 0 : return 0;
364 : }
365 :
366 :
367 :
368 0 : int koolanceCtrl::initialConnect()
369 : {
370 : int rv;
371 :
372 0 : std::vector<unsigned char> com;
373 0 : com.resize(3, '\0');
374 0 : com[0] = 0xCF;
375 0 : com[1] = 0x01;
376 0 : com[2] = 0x08;
377 :
378 0 : rv = write(m_fileDescrip, com.data(), com.size());
379 :
380 0 : if(rv < 0)
381 : {
382 0 : log<software_error>({__FILE__,__LINE__, errno, "error from write"});
383 0 : ::close(m_fileDescrip);
384 0 : m_fileDescrip = 0;
385 0 : state(stateCodes::NOTCONNECTED);
386 :
387 0 : return -1;
388 : }
389 :
390 0 : std::vector<unsigned char> resp;
391 0 : resp.resize(51);
392 :
393 0 : mx::sys::milliSleep(1000); //Sleep for a long time to make sure device responds
394 : int readBytes;
395 0 : rv = tty::ttyReadRaw(resp, readBytes, m_fileDescrip, 1000); ///\todo needs to be iodevice
396 :
397 0 : if(rv < 0)
398 : {
399 0 : log<software_error>({__FILE__,__LINE__, errno, "error from read"});
400 0 : ::close(m_fileDescrip);
401 0 : m_fileDescrip = 0;
402 0 : state(stateCodes::NOTCONNECTED);
403 :
404 0 : return -1;
405 : }
406 :
407 0 : if(readBytes == 43)
408 : {
409 0 : log<text_log>("found protocol 1 device");
410 0 : m_protocolChars = 43;
411 : }
412 0 : else if(readBytes == 51)
413 : {
414 0 : log<text_log>("found protocol 2 device");
415 0 : m_protocolChars = 51;
416 : }
417 : else
418 : {
419 0 : return -1;
420 : }
421 :
422 0 : if(!m_indiSetup)
423 : {
424 0 : if(readBytes == 43)
425 : {
426 0 : REG_INDI_NEWPROP_NOCB(m_indiP_pumplvl, "pump_level", pcf::IndiProperty::Number);
427 0 : m_indiP_pumplvl.add(pcf::IndiElement("current"));
428 :
429 0 : REG_INDI_NEWPROP_NOCB(m_indiP_fanlvl, "fan_level", pcf::IndiProperty::Number);
430 0 : m_indiP_fanlvl.add(pcf::IndiElement("current"));
431 : }
432 : else
433 : {
434 0 : createStandardIndiNumber<int>( m_indiP_pumplvl, "pump_level", 1, 10, 1, "%d", "Pump Level", "Lab");
435 0 : registerIndiPropertyNew( m_indiP_pumplvl, INDI_NEWCALLBACK(m_indiP_pumplvl));
436 :
437 0 : createStandardIndiNumber<int>( m_indiP_fanlvl, "fan_level", 0, 100, 1, "%d", "Fan Level", "Lab");
438 0 : registerIndiPropertyNew( m_indiP_fanlvl, INDI_NEWCALLBACK(m_indiP_fanlvl));
439 : }
440 :
441 0 : m_indiSetup = true;
442 : }
443 :
444 0 : return 0;
445 0 : }
446 :
447 0 : int koolanceCtrl::getStatus()
448 : {
449 : int rv;
450 :
451 0 : std::vector<unsigned char> com;
452 0 : com.resize(3, '\0');
453 0 : com[0] = 0xCF;
454 0 : com[1] = 0x01;
455 0 : com[2] = 0x08;
456 :
457 0 : rv = write(m_fileDescrip, com.data(), com.size());
458 :
459 0 : if(rv < 0)
460 : {
461 0 : log<software_error>({__FILE__,__LINE__, errno, "error from write"});
462 0 : ::close(m_fileDescrip);
463 0 : m_fileDescrip = 0;
464 0 : state(stateCodes::NOTCONNECTED);
465 :
466 0 : return -1;
467 : }
468 :
469 0 : std::string resp;
470 :
471 0 : rv = tty::ttyRead(resp, m_protocolChars, m_fileDescrip, 1000); ///\todo needs to be iodevice
472 :
473 0 : if(rv < 0)
474 : {
475 0 : log<software_error>({__FILE__,__LINE__, errno, "error from read"});
476 0 : ::close(m_fileDescrip);
477 0 : m_fileDescrip = 0;
478 0 : state(stateCodes::NOTCONNECTED);
479 :
480 0 : return -1;
481 : }
482 :
483 0 : if(resp.size() == m_protocolChars)
484 : {
485 0 : m_liqTemp = ((float) (( (unsigned char)resp[2] << 8) + (unsigned char)resp[3]-2000)) / 10.0;
486 0 : m_flowRate = ( (float) ((unsigned char)resp[12] << 8) + (unsigned char)resp[13]) / 10.0;
487 0 : m_fanRPM = ((unsigned char)resp[8] << 8) + (unsigned char)resp[9];
488 0 : m_pumpRPM = ((unsigned char)resp[10] << 8) + (unsigned char)resp[11];
489 0 : m_fanLvl = (unsigned char)resp[15];
490 0 : m_pumpLvl = (unsigned char)resp[17];
491 :
492 0 : recordCooler();
493 : // std::cout << std::dec;
494 : // std::cout << "liq. temp: " << m_liqTemp << " C\n";
495 : // std::cout << "flow rate: " << m_flowRate << " LPM\n";
496 : // std::cout << "pump lvl: " << m_pumpLvl << "\n";
497 : // std::cout << "pump speed:" << m_pumpRPM << " RPM\n";
498 : // std::cout << "fan lvl: " << m_fanLvl << "\n";
499 : // std::cout << "fan speed:" << m_fanRPM << " RPM\n";
500 :
501 0 : updateIfChanged(m_indiP_status, "liquid_temp", m_liqTemp);
502 0 : updateIfChanged(m_indiP_status, "flow_rate", m_flowRate);
503 0 : updateIfChanged(m_indiP_status, "pump_rpm", m_pumpRPM);
504 0 : updateIfChanged(m_indiP_status, "fan_rpm", m_fanRPM);
505 0 : updateIfChanged(m_indiP_pumplvl, "current", m_pumpLvl);
506 0 : updateIfChanged(m_indiP_fanlvl, "current", m_fanLvl);
507 :
508 0 : return 0;
509 : }
510 : else
511 : {
512 0 : log<software_error>({__FILE__,__LINE__, std::string("wrong response size (") + std::to_string(resp.size()) + ") returned"});
513 0 : ::close(m_fileDescrip);
514 0 : m_fileDescrip = 0;
515 0 : state(stateCodes::NOTCONNECTED);
516 :
517 0 : return -1;
518 : }
519 0 : }
520 :
521 0 : int koolanceCtrl::setPumpLvl( int lvl )
522 : {
523 0 : if(m_protocolChars == 43) return 0;
524 :
525 : int rv;
526 :
527 0 : std::vector<unsigned char> com;
528 0 : com.resize(m_protocolChars, '\0');
529 0 : com[0] = 0xCF;
530 0 : com[1] = 0x04;
531 :
532 0 : com[15] = m_fanLvl;
533 0 : com[17] = lvl;
534 :
535 : //Disable most stuff.
536 0 : for(size_t n = 20; n <m_protocolChars-1; ++n) com[n] = 0xAA;
537 :
538 : //Preserve units
539 0 : if(m_protocolChars > 43)
540 : {
541 0 : com[44] = 0;
542 0 : com[45] = 0x0001;
543 0 : com[46] = 0;
544 0 : com[47] = 0;
545 0 : com[48] = 0;
546 0 : com[49] = 0;
547 : }
548 :
549 0 : int checksum = 0;
550 0 : for(size_t n = 0; n <m_protocolChars-1; ++n) checksum += com[n];
551 0 : com[m_protocolChars-1] = checksum % 0x64;
552 :
553 0 : rv = write(m_fileDescrip, com.data(), com.size());
554 :
555 0 : if(rv < 0)
556 : {
557 0 : log<software_error>({__FILE__,__LINE__, errno, "error from write"});
558 0 : ::close(m_fileDescrip);
559 0 : m_fileDescrip = 0;
560 0 : state(stateCodes::NOTCONNECTED);
561 :
562 0 : return -1;
563 : }
564 :
565 0 : log<text_log>("set pump level to " + std::to_string(lvl));
566 :
567 0 : return 0;
568 0 : }
569 :
570 0 : int koolanceCtrl::setFanLvl( int lvl )
571 : {
572 0 : if(m_protocolChars == 43) return 0;
573 :
574 : int rv;
575 :
576 0 : std::vector<unsigned char> com;
577 0 : com.resize(m_protocolChars, '\0');
578 0 : com[0] = 0xCF;
579 0 : com[1] = 0x04;
580 :
581 0 : com[15] = lvl;
582 0 : com[17] = m_pumpLvl;
583 :
584 : //Disable most stuff.
585 0 : for(size_t n = 20; n <m_protocolChars-1; ++n) com[n] = 0xAA;
586 :
587 : //Preserve units
588 0 : if(m_protocolChars > 43)
589 : {
590 0 : com[44] = 0;
591 0 : com[45] = 0x0001;
592 0 : com[46] = 0;
593 0 : com[47] = 0;
594 0 : com[48] = 0;
595 0 : com[49] = 0;
596 : }
597 :
598 0 : int checksum = 0;
599 0 : for(size_t n = 0; n <m_protocolChars-1; ++n) checksum += com[n];
600 0 : com[m_protocolChars-1] = checksum % 0x64;
601 :
602 0 : rv = write(m_fileDescrip, com.data(), com.size());
603 :
604 0 : if(rv < 0)
605 : {
606 0 : log<software_error>({__FILE__,__LINE__, errno, "error from write"});
607 0 : ::close(m_fileDescrip);
608 0 : m_fileDescrip = 0;
609 0 : state(stateCodes::NOTCONNECTED);
610 :
611 0 : return -1;
612 : }
613 :
614 0 : log<text_log>("set fan level to " + std::to_string(lvl));
615 :
616 0 : return 0;
617 0 : }
618 :
619 0 : INDI_NEWCALLBACK_DEFN(koolanceCtrl, m_indiP_pumplvl)(const pcf::IndiProperty &ipRecv)
620 : {
621 0 : if(ipRecv.getName() != m_indiP_pumplvl.getName())
622 : {
623 0 : log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
624 0 : return -1;
625 : }
626 :
627 0 : int lvl = -1;
628 :
629 0 : if( ipRecv.find("current") )
630 : {
631 0 : lvl = ipRecv["current"].get<int>();
632 : }
633 :
634 0 : if( ipRecv.find("target") )
635 : {
636 0 : lvl = ipRecv["target"].get<int>();
637 : }
638 :
639 0 : if(lvl < 1 || lvl > 10)
640 : {
641 0 : log<software_error>({__FILE__,__LINE__, "Pump level out of range"});
642 0 : return 0;
643 : }
644 :
645 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
646 0 : updateIfChanged(m_indiP_pumplvl, "target", lvl);
647 0 : return setPumpLvl(lvl);
648 :
649 :
650 0 : }
651 :
652 0 : INDI_NEWCALLBACK_DEFN(koolanceCtrl, m_indiP_fanlvl)(const pcf::IndiProperty &ipRecv)
653 : {
654 0 : if(ipRecv.getName() != m_indiP_fanlvl.getName())
655 : {
656 0 : log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
657 0 : return -1;
658 : }
659 :
660 :
661 0 : int lvl = -1;
662 :
663 0 : if( ipRecv.find("current") )
664 : {
665 0 : lvl = ipRecv["current"].get<int>();
666 : }
667 :
668 0 : if( ipRecv.find("target") )
669 : {
670 0 : lvl = ipRecv["target"].get<int>();
671 : }
672 :
673 0 : if(lvl < 0 || lvl > 100)
674 : {
675 0 : log<software_error>({__FILE__,__LINE__, "Fan level out of range"});
676 0 : return 0;
677 : }
678 :
679 0 : std::unique_lock<std::mutex> lock(m_indiMutex);
680 0 : updateIfChanged(m_indiP_fanlvl, "target", lvl);
681 0 : return setFanLvl(lvl);
682 :
683 : return 0;
684 0 : }
685 :
686 : inline
687 0 : int koolanceCtrl::checkRecordTimes()
688 : {
689 0 : return telemeter<koolanceCtrl>::checkRecordTimes(telem_cooler());
690 : }
691 :
692 : inline
693 0 : int koolanceCtrl::recordTelem( const telem_cooler * )
694 : {
695 0 : return recordCooler(true);
696 : }
697 :
698 : inline
699 0 : int koolanceCtrl::recordCooler( bool force )
700 : {
701 : static float last_liqTemp = std::numeric_limits<float>::max();
702 : static float last_flowRate = std::numeric_limits<float>::max();
703 : static int last_pumpLvl = std::numeric_limits<int>::max();
704 : static int last_pumpRPM = std::numeric_limits<int>::max();
705 : static int last_fanRPM = std::numeric_limits<int>::max();
706 : static int last_fanLvl = std::numeric_limits<int>::max();
707 :
708 0 : if( m_liqTemp != last_liqTemp || m_flowRate != last_flowRate || m_pumpLvl != last_pumpLvl ||
709 0 : m_pumpRPM != last_pumpRPM || m_fanRPM != last_fanRPM || m_fanLvl != last_fanLvl || force )
710 : {
711 0 : telem<telem_cooler>({m_liqTemp, m_flowRate, (uint8_t) m_pumpLvl, (uint16_t) m_pumpRPM, (uint8_t) m_fanLvl, (uint16_t) m_fanRPM});
712 :
713 0 : last_liqTemp = m_liqTemp;
714 0 : last_flowRate = m_flowRate;
715 0 : last_pumpLvl = m_pumpLvl;
716 0 : last_pumpRPM = m_pumpRPM;
717 0 : last_fanLvl = m_fanLvl;
718 0 : last_fanRPM = m_fanRPM;
719 : }
720 :
721 0 : return 0;
722 : }
723 :
724 : } //namespace app
725 : } //namespace MagAOX
726 :
727 : #endif //koolanceCtrl_hpp
|