API
 
Loading...
Searching...
No Matches
acesxeCtrl.hpp
Go to the documentation of this file.
1/** \file acesxeCtrl.hpp
2 * \brief The MagAO-X XXXXXX header file
3 *
4 * \ingroup acesxeCtrl_files
5 */
6
7#ifndef acesxeCtrl_hpp
8#define acesxeCtrl_hpp
9
10extern "C"
11{
12 #include "ArcusPerformaxDriver.h"
13}
14
15#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
16#include "../../magaox_git_version.h"
17
18/** \defgroup acesxeCtrl
19 * \brief The XXXXXX application to do YYYYYYY
20 *
21 * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
22 *
23 * \ingroup apps
24 *
25 */
26
27/** \defgroup acesxeCtrl_files
28 * \ingroup acesxeCtrl
29 */
30
31namespace MagAOX
32{
33namespace app
34{
35
36/// The MagAO-X xxxxxxxx
37/**
38 * \ingroup acesxeCtrl
39 */
40class acesxeCtrl : public MagAOXApp<true>
41{
42
43 //Give the test harness access.
44 friend class acesxeCtrl_test;
45
46protected:
47
48 /** \name Configurable Parameters
49 *@{
50 */
51
52 //here add parameters which will be config-able at runtime
53
54 ///@}
55
56
57 AR_HANDLE m_handle {nullptr}; //usb handle
58
59
60 float m_windSpeed {10};
61 bool m_forward {true};
62
63 int m_lspd {150}; //This sets a lower limit of 0.9 m/s.
64 int m_hspd {300};
65
66public:
67 /// Default c'tor.
68 acesxeCtrl();
69
70 /// D'tor, declared and defined for noexcept.
71 ~acesxeCtrl() noexcept
72 {}
73
74 virtual void setupConfig();
75
76 /// Implementation of loadConfig logic, separated for testing.
77 /** This is called by loadConfig().
78 */
79 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
80
81 virtual void loadConfig();
82
83 /// Startup function
84 /**
85 *
86 */
87 virtual int appStartup();
88
89 /// Implementation of the FSM for acesxeCtrl.
90 /**
91 * \returns 0 on no critical error
92 * \returns -1 on an error requiring shutdown
93 */
94 virtual int appLogic();
95
96 /// Shutdown the app.
97 /**
98 *
99 */
100 virtual int appShutdown();
101
102
103 int sendRecv( std::string & sout,
104 const std::string & com
105 );
106
107
108 float hspd();
109
110 int hspd(int hspd);
111
112 float windSpeed();
113
114 int windSpeed(float ws);
115
116
117 int start();
118
119 int stop();
120
121 int abort();
122
123 pcf::IndiProperty m_indiP_windspeed;
124
125 pcf::IndiProperty m_indiP_start;
126 pcf::IndiProperty m_indiP_stop;
127 pcf::IndiProperty m_indiP_abort;
128
133
134};
135
136acesxeCtrl::acesxeCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
137{
138 m_powerMgtEnabled = true;
139 return;
140}
141
143{
144}
145
146int acesxeCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
147{
148
149 static_cast<void>(_config);
150
151 return 0;
152}
153
155{
156 loadConfigImpl(config);
157}
158
160{
161
162 //These can be made config parametrs
163 if(!fnPerformaxComSetTimeouts(5000,5000))
164 {
165 log<software_error>({__FILE__, __LINE__, "error setting timeouts"});
166 return -1;
167 }
168
169 createStandardIndiNumber<float>( m_indiP_windspeed, "windspeed", -60, 60, 0.0, "%f");
171 m_indiP_windspeed["target"].set<float>(0);
172 m_indiP_windspeed["current"].set<float>(0);
173
174 createStandardIndiRequestSw( m_indiP_start, "start", "Start", "Turb Sim Controls");
176
177 createStandardIndiRequestSw( m_indiP_stop, "stop", "Stop", "Turb Sim Controls");
179
180 createStandardIndiRequestSw( m_indiP_abort, "abort", "Abort", "Turb Sim Controls");
182
183 m_powerState = 1;
185
186
188 return 0;
189}
190
192{
194 {
196 }
197
199 {
201
202 std::lock_guard<std::mutex> guard(m_indiMutex);
203
205 {
206 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
207 log<software_error>({__FILE__, __LINE__, "error in fnPerformaxComGetNumDevices"});
208 return 0;
209 }
210
211 if(num<1)
212 {
213 if(!stateLogged())
214 {
215 log<text_log>("ACE-SXE not found");
216 }
217 return 0;
218 }
219
220 if(num>1)
221 {
222 log<text_log>("Too many ACE-SXEs found. I can't handle this.", logPrio::LOG_CRITICAL);
223 return -1;
224 }
225
227
228 elevatedPrivileges elPriv(this);
229
231 {
232 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
233 log<software_error>({__FILE__, __LINE__, "error acquiring product serial number"});
234 return 0;
235 }
236 lpDeviceString[sizeof(lpDeviceString) - 1] = '\0'; //don't trust too much
237
238 std::string serial = lpDeviceString;
239
241 {
242 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
243 log<software_error>({__FILE__, __LINE__, "errovr acquiring product description"});
244 return 0;
245 }
246 lpDeviceString[sizeof(lpDeviceString) - 1] = '\0'; //don't trust too much
247
248 std::string descrip = lpDeviceString;
249
250 log<text_log>("found ACE-SXE: " + descrip + " " + serial);
251
253 }
254
256 {
257 //setup the connection
258
259 std::lock_guard<std::mutex> guard(m_indiMutex);
260
261 if(m_handle)
262 {
264 {
265 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
266 log<software_error>({__FILE__, __LINE__, "error closing existing handle"});
267 }
268 m_handle = nullptr;
269 }
270
271
272 {
273 elevatedPrivileges elPriv(this);
274
276 {
277 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
278 log<software_error>({__FILE__, __LINE__, "error closing existing handle"});
280 return 0;
281 }
282 }
283
285 {
286 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
287 log<software_error>({__FILE__, __LINE__, "error flushing"});
289 return 0;
290 }
291
292 char out[64];
293 char in[64];
294
295 strncpy(out, "ID", sizeof(out));
296 if( !fnPerformaxComSendRecv(m_handle, out, sizeof(out), sizeof(in), in) )
297 {
298 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
299 log<software_error>({__FILE__, __LINE__, "error getting ID"});
301 return 0;
302 }
303 in[sizeof(in)-1] = '\0';
304 std::string id = in;
305
306 strncpy(out, "DN", sizeof(out)); //read current
307 if(!fnPerformaxComSendRecv(m_handle, out, sizeof(out), sizeof(in), in))
308 {
309 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
310 log<software_error>({__FILE__, __LINE__, "error getting DN"});
312 return 0;
313 }
314
315 std::string dn = in;
316
318 log<text_log>("connected to ACE-SXE " + id + " " + dn);
319
320 }
321
322
324 {
325 std::string resp;
326
327 std::lock_guard<std::mutex> guard(m_indiMutex);
328
329 //Check the parameters
330 if(sendRecv(resp, "EDIO") != 0)
331 {
332 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
335 return 0;
336 }
337 log<text_log>( "EDIO=" + resp);
338
339 if(sendRecv(resp, "POL") != 0)
340 {
341 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
344 return 0;
345 }
346 log<text_log>( "POL=" + resp);
347
348 if(sendRecv(resp, "ACC") != 0)
349 {
350 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
353 return 0;
354 }
355 log<text_log>( "ACC=" + resp);
356
357 if(sendRecv(resp, "LSPD=" + std::to_string(m_lspd)) != 0)
358 {
359 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
362 return 0;
363 }
364 if(resp != "OK")
365 {
366 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
367 log<software_error>({__FILE__, __LINE__, "not OK from LSPD="});
369 return 0;
370 }
371 log<text_log>("set LSPD=" + std::to_string(m_lspd) );
372
373 if( windSpeed(m_windSpeed) != 0)
374 {
375 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
378 return 0;
379 }
380
381
382 if(sendRecv(resp, "MST") != 0)
383 {
384 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
387 return 0;
388 }
389
390 int mst = stoi(resp);
391
392 if(mst & 1 || mst & 2 || mst & 4) state(stateCodes::OPERATING);
394
395 }
396
397 if(state() == stateCodes::ERROR)
398 {
399 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
400
401 if(m_handle)
402 {
404 m_handle = nullptr;
405 }
406
408
409 return 0;
410
411 }
412
414 {
415 std::string smst;
416 if(sendRecv(smst, "MST") != 0)
417 {
418 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
421 return 0;
422 }
423
424 int mst = stoi(smst);
425
426 if(mst & 1 || mst & 2 || mst & 4) state(stateCodes::OPERATING);
428
429 std::lock_guard<std::mutex> guard(m_indiMutex);
430
432 }
433 else
434 {
435 if(state() == stateCodes::POWEROFF || state() == stateCodes::POWERON) return 0;
436 log<software_error>({__FILE__,__LINE__, "bad state"});
437 }
438
439 return 0;
440}
441
443{
444 return 0;
445}
446
447int acesxeCtrl::sendRecv( std::string & sout, const std::string & com)
448{
449 char out[64];
450 char in[64];
451
452 //Check the parameters
453 strncpy(out, com.c_str(), sizeof(out)-1);
454 if( !fnPerformaxComSendRecv(m_handle, out, sizeof(out), sizeof(in), in) )
455 {
456 if(m_powerState != 1 || m_powerTargetState != 1) return -1; //error, but don't log
457 log<software_error>({__FILE__, __LINE__, std::string("error getting ") + out});
459 return -1;
460 }
461 in[sizeof(in)-1] = '\0'; //trust but verify
462 sout = in;
463
464 return 0;
465}
466
468{
469 return m_hspd;
470}
471
472int acesxeCtrl::hspd(int hspd)
473{
474 std::string resp;
475
476 //Check the parameters
477 if(sendRecv(resp, "HSPD="+std::to_string(hspd)) != 0)
478 {
479 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
482 return -1;
483 }
484 if(resp != "OK")
485 {
486 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
487 log<software_error>({__FILE__, __LINE__, "not OK from HSPD="});
489 return -1;
490 }
491
492 if(sendRecv(resp, "HSPD") != 0)
493 {
494 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
497 return -1;
498 }
499
500 m_hspd = std::stoi(resp);
501
502 log<text_log>("set HSPD to " + std::to_string(m_hspd));
503
504 return 0;
505
506}
507
509{
510 return (1. - 2.*(m_forward-1)) * m_hspd/9600.*60. * (12.7/12.0); //(12.7 m/s per 12 rpm)
511
512}
513
515{
516 if(ws < 0) m_forward = false;
517 else m_forward = true;
518
519 if(ws < -60)
520 {
521 ws = -60;
522 log<text_log>("wind speed limited to -60 m/s", logPrio::LOG_NOTICE);
523 }
524 if(ws > 60)
525 {
526 ws = 60;
527 log<text_log>("wind speed limited to 60 m/s", logPrio::LOG_NOTICE);
528 }
529
530 float ll = m_lspd/9600.*60. * (12.7/12.0);
532 {
533 log<text_log>("wind speed below minimum of 0.9 m/s", logPrio::LOG_NOTICE);
534 }
535
536 if(ws >= 0 && ws < ll)
537 {
538 log<text_log>("wind speed below minimum of 0.9 m/s", logPrio::LOG_NOTICE);
539 }
540
541
542 int h = (12.0/12.7) / 60. * 9600 * fabs(ws);
543
544 if(hspd(h) != 0)
545 {
546 if(m_powerState != 1 || m_powerTargetState != 1) return -1;
549 return -1;
550 }
551
552 log<text_log>("set wind speed to " + std::to_string(windSpeed()));
553
556
557 return 0;
558
559}
560
562{
563 std::string resp;
564
565 std::string com = "EO=1";
566
567 if(sendRecv(resp, com) != 0)
568 {
569 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
572 return -1;
573 }
574 if(resp != "OK")
575 {
576 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
577 log<software_error>({__FILE__, __LINE__, "not OK from " + com});
579 return -1;
580 }
581
582 com = "J";
583 if(m_forward) com += "+";
584 else com += "-";
585
586 if(sendRecv(resp, com) != 0)
587 {
588 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
591 return -1;
592 }
593 if(resp != "OK")
594 {
595 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
596 log<software_error>({__FILE__, __LINE__, "not OK from " + com});
598 return -1;
599 }
600
601 log<text_log>("started spinning turbulence simulator", logPrio::LOG_NOTICE);
602 return 0;
603}
604
606{
607 std::string resp;
608
609
610 if(sendRecv(resp, "STOP") != 0)
611 {
612 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
615 return -1;
616 }
617 if(resp != "OK")
618 {
619 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
620 log<software_error>({__FILE__, __LINE__, "not OK from STOP"});
622 return -1;
623 }
624
625 std::string com = "EO=0";
626
627 if(sendRecv(resp, com) != 0)
628 {
629 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
632 return -1;
633 }
634 if(resp != "OK")
635 {
636 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
637 log<software_error>({__FILE__, __LINE__, "not OK from " + com});
639 return -1;
640 }
641
642 log<text_log>("stopped spinning turbulence simulator", logPrio::LOG_NOTICE);
643 return 0;
644}
645
647{
648 std::string resp;
649
650
651 if(sendRecv(resp, "ABORT") != 0)
652 {
653 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
656 return -1;
657 }
658 if(resp != "OK")
659 {
660 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
661 log<software_error>({__FILE__, __LINE__, "not OK from ABORT"});
663 return -1;
664 }
665
666 std::string com = "EO=0";
667
668 if(sendRecv(resp, com) != 0)
669 {
670 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
673 return -1;
674 }
675 if(resp != "OK")
676 {
677 if(m_powerState != 1 || m_powerTargetState != 1) return 0;
678 log<software_error>({__FILE__, __LINE__, "not OK from " + com});
680 return -1;
681 }
682
683 log<text_log>("aborted spinning turbulence simulator", logPrio::LOG_NOTICE);
684 return 0;
685}
686
687INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf::IndiProperty &ipRecv)
688{
689 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_windspeed, ipRecv);
690
691 float ws = 0;
692
693 if(ipRecv.find("current"))
694 {
695 ws = ipRecv["current"].get<double>();
696 }
697
698 if(ipRecv.find("target"))
699 {
700 ws = ipRecv["target"].get<double>();
701 }
702
703 if(ws == 0) return 0;
704
705 std::lock_guard<std::mutex> guard(m_indiMutex);
706
707 updateIfChanged(m_indiP_windspeed, "target", ws, INDI_OK);
708
709 return windSpeed(ws);
710
711
712 return -1;
713}
714
715INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_start )(const pcf::IndiProperty &ipRecv)
716{
717 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_start, ipRecv);
718
719 if(!ipRecv.find("request")) return 0;
720
721 std::unique_lock<std::mutex> lock(m_indiMutex);
722
723 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
724 {
725 return start();
726 }
727
728 return 0;
729}
730
731INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_stop )(const pcf::IndiProperty &ipRecv)
732{
734
735 if(!ipRecv.find("request")) return 0;
736
737 std::unique_lock<std::mutex> lock(m_indiMutex);
738
739 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
740 {
741 return stop();
742 }
743
744 return 0;
745}
746
747INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_abort )(const pcf::IndiProperty &ipRecv)
748{
749 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_abort, ipRecv);
750
751 if(!ipRecv.find("request")) return 0;
752
753 std::unique_lock<std::mutex> lock(m_indiMutex);
754
755 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
756 {
757 return abort();
758 }
759
760 return 0;
761}
762
763} //namespace app
764} //namespace MagAOX
765
766#endif //acesxeCtrl_hpp
AR_BOOL fnPerformaxComClose(AR_HANDLE device_handle)
AR_BOOL fnPerformaxComFlush(AR_HANDLE device_handle)
AR_BOOL fnPerformaxComGetNumDevices(AR_DWORD *numDevices)
AR_BOOL fnPerformaxComGetProductString(AR_DWORD dwNumDevice, AR_VOID *lpDeviceString, AR_DWORD dwOptions)
AR_BOOL fnPerformaxComSetTimeouts(AR_DWORD dwReadTimeout, AR_DWORD dwWriteTimeout)
AR_BOOL fnPerformaxComSendRecv(AR_HANDLE device_handle, AR_VOID *wBuffer, AR_DWORD dwNumBytesToWrite, AR_DWORD dwNumBytesToRead, AR_VOID *rBuffer)
AR_BOOL fnPerformaxComOpen(AR_DWORD dwDeviceNum, AR_HANDLE *device_handle)
#define PERFORMAX_RETURN_SERIAL_NUMBER
#define PERFORMAX_MAX_DEVICE_STRLEN
libusb_device_handle * AR_HANDLE
long AR_DWORD
#define PERFORMAX_RETURN_DESCRIPTION
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.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int m_powerState
Current power state, 1=On, 0=Off, -1=Unk.
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.
int m_powerTargetState
Current target power state, 1=On, 0=Off, -1=Unk.
The MagAO-X xxxxxxxx.
virtual void loadConfig()
int sendRecv(std::string &sout, const std::string &com)
virtual int appStartup()
Startup function.
virtual void setupConfig()
pcf::IndiProperty m_indiP_start
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
INDI_NEWCALLBACK_DECL(acesxeCtrl, m_indiP_windspeed)
friend class acesxeCtrl_test
pcf::IndiProperty m_indiP_windspeed
virtual int appLogic()
Implementation of the FSM for acesxeCtrl.
acesxeCtrl()
Default c'tor.
~acesxeCtrl() noexcept
D'tor, declared and defined for noexcept.
INDI_NEWCALLBACK_DECL(acesxeCtrl, m_indiP_start)
pcf::IndiProperty m_indiP_abort
virtual int appShutdown()
Shutdown the app.
pcf::IndiProperty m_indiP_stop
INDI_NEWCALLBACK_DECL(acesxeCtrl, m_indiP_abort)
INDI_NEWCALLBACK_DECL(acesxeCtrl, m_indiP_stop)
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
@ OPERATING
The device is operating, other than homing.
@ POWEROFF
The device power is off.
@ NODEVICE
No device exists for the application to control.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
@ POWERON
The device power is on.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_OK
Definition indiUtils.hpp:29
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)