API
 
Loading...
Searching...
No Matches
t2wOffloader.hpp
Go to the documentation of this file.
1/** \file t2wOffloader.hpp
2 * \brief The MagAO-X tweeter to woofer offloading manager
3 *
4 * \ingroup app_files
5 */
6
7#ifndef t2wOffloader_hpp
8#define t2wOffloader_hpp
9
10#include <limits>
11
12#include <mx/improc/eigenCube.hpp>
13#include <mx/improc/eigenImage.hpp>
14#include <mx/sigproc/gramSchmidt.hpp>
15#include <mx/math/templateBLAS.hpp>
16
17#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
18#include "../../magaox_git_version.h"
19
20namespace MagAOX
21{
22namespace app
23{
24
25/** \defgroup t2wOffloader Tweeter to Woofer Offloading
26 * \brief Monitors the averaged tweeter shape, and sends it to the woofer.
27 *
28 * <a href="../handbook/operating/software/apps/t2wOffloader.html">Application Documentation</a>
29 *
30 * \ingroup apps
31 *
32 */
33
34/** \defgroup t2wOffloader_files Tweeter to Woofer Offloading
35 * \ingroup t2wOffloader
36 */
37
38/** MagAO-X application to control offloading the tweeter to the woofer.
39 *
40 * \ingroup t2wOffloader
41 *
42 */
43class t2wOffloader : public MagAOXApp<true>, public dev::shmimMonitor<t2wOffloader>
44{
45
46 //Give the test harness access.
47 friend class t2wOffloader_test;
48
49 friend class dev::shmimMonitor<t2wOffloader>;
50
51 //The base shmimMonitor type
53
54 ///Floating point type in which to do all calculations.
55 typedef float realT;
56
57protected:
58
59 /** \name Configurable Parameters
60 *@{
61 */
62
63 std::string m_twRespMPath;
64
65 std::string m_dmChannel ;
66
67 std::string m_fpsSource {"camwfs"};
68 std::string m_navgSource {"dmtweeter-avg"};
69 float m_gain {0.1};
70 float m_leak {0.0};
71
72 float m_actLim {7.0}; ///< the upper limit on woofer actuator commands. default is 7.0.
73
74 std::string m_tweeterModeFile; ///< File containing the tweeter modes to use for offloading
75 std::string m_tweeterMaskFile;
76
77 int m_maxModes {50};
78
79 int m_numModes {0};
80 ///@}
81
82 mx::improc::eigenImage<realT> m_twRespM;
83 mx::improc::eigenImage<realT> m_tweeter;
84 mx::improc::eigenImage<realT> m_woofer;
85 mx::improc::eigenImage<realT> m_wooferDelta;
86 mx::improc::eigenImage<realT> m_modeAmps;
87
88
89 mx::improc::eigenImage<realT> m_tweeterMask;
90
91 mx::improc::eigenCube<float> m_tModesOrtho;
92
93 mx::improc::eigenCube<float> m_wModes;
94
95 float m_fps {0}; ///< Current FPS from the FPS source.
96 int m_navg {0}; ///< Current navg from the averager
97
98 float m_effFPS {0};
99
101 uint32_t m_dmWidth {0}; ///< The width of the image
102 uint32_t m_dmHeight {0}; ///< The height of the image.
103
104 uint8_t m_dmDataType{0}; ///< The ImageStreamIO type code.
105 size_t m_dmTypeSize {0}; ///< The size of the type, in bytes.
106
107 bool m_dmOpened {false};
108 bool m_dmRestart {false};
109
110 bool m_offloading {false};
111
112public:
113 /// Default c'tor.
114 t2wOffloader();
115
116 /// D'tor, declared and defined for noexcept.
119
120 virtual void setupConfig();
121
122 /// Implementation of loadConfig logic, separated for testing.
123 /** This is called by loadConfig().
124 */
125 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
126
127 virtual void loadConfig();
128
129 /// Startup function
130 /**
131 *
132 */
133 virtual int appStartup();
134
135 /// Implementation of the FSM for t2wOffloader.
136 /**
137 * \returns 0 on no critical error
138 * \returns -1 on an error requiring shutdown
139 */
140 virtual int appLogic();
141
142 /// Shutdown the app.
143 /**
144 *
145 */
146 virtual int appShutdown();
147
148 int updateFPS();
149
150 int allocate( const dev::shmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
151
152 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
153 const dev::shmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
154 );
155
156
157 int zero();
158
159 int prepareModes();
160
161protected:
162
163
164
165 pcf::IndiProperty m_indiP_gain;
166 pcf::IndiProperty m_indiP_leak;
167 pcf::IndiProperty m_indiP_actLim;
168
169 pcf::IndiProperty m_indiP_zero;
170
171 pcf::IndiProperty m_indiP_numModes;
172
173 pcf::IndiProperty m_indiP_offloadToggle;
174
178
180
182
184
185 pcf::IndiProperty m_indiP_fpsSource;
187
188 pcf::IndiProperty m_indiP_navgSource;
190
191 pcf::IndiProperty m_indiP_fps;
192};
193
194inline
195t2wOffloader::t2wOffloader() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
196{
197 return;
198}
199
200inline
202{
204
205 config.add("integrator.fpsSource", "", "integrator.fpsSource", argType::Required, "integrator", "fpsSource", false, "string", "Device name for getting fps of the loop. This device should have *.fps.current. Default is camwfs");
206 config.add("integrator.navgSource", "", "integrator.navgSource", argType::Required, "integrator", "navgSource", false, "string", "Device name for getting navg of tweeter-ave. This device should have *.fps.current. Default is dmtweeter-avg.");
207
208 config.add("offload.respMPath", "", "offload.respMPath", argType::Required, "offload", "respMPath", false, "string", "The path to the response matrix.");
209 config.add("offload.channel", "", "offload.channel", argType::Required, "offload", "channel", false, "string", "The DM channel to offload to.");
210
211 config.add("offload.gain", "", "offload.gain", argType::Required, "offload", "gain", false, "float", "The starting offload gain. Default is 0.1.");
212 config.add("offload.leak", "", "offload.leak", argType::Required, "offload", "leak", false, "float", "The starting offload leak. Default is 0.0.");
213 config.add("offload.startupOffloading", "", "offload.startupOffloading", argType::Required, "offload", "startupOffloading", false, "bool", "Flag controlling whether offloading is on at startup. Default is false.");
214 config.add("offload.actLim", "", "offload.actLim", argType::Required, "offload", "actLim", false, "float", "The woofer actuator command limit. Default is 7.0.");
215
216 config.add("offload.tweeterModes", "", "offload.tweeterModes", argType::Required, "offload", "tweeterModes", false, "string", "File containing the tweeter modes to use for offloading");
217 config.add("offload.tweeterMask", "", "offload.tweeterMask", argType::Required, "offload", "tweeterMask", false, "string", "File containing the tweeter mask.");
218 config.add("offload.maxModes", "", "offload.maxModes", argType::Required, "offload", "maxModes", false, "string", "Maximum number of modes for modal offloading.");
219 config.add("offload.numModes", "", "offload.numModes", argType::Required, "offload", "numModes", false, "string", "Number of modes to offload. 0 means use actuator offloading.");
220}
221
222inline
223int t2wOffloader::loadConfigImpl( mx::app::appConfigurator & _config )
224{
225
227
228 _config(m_fpsSource, "integrator.fpsSource");
229 _config(m_navgSource, "integrator.navgSource");
230
231 _config(m_twRespMPath, "offload.respMPath");
232 _config(m_dmChannel, "offload.channel");
233 _config(m_gain, "offload.gain");
234 _config(m_leak, "offload.leak");
235 _config(m_actLim, "offload.actLim");
236 _config(m_tweeterModeFile, "offload.tweeterModes");
237 _config(m_tweeterMaskFile, "offload.tweeterMask");
238 _config(m_maxModes, "offload.maxModes");
239 _config(m_numModes, "offload.numModes");
240
241 bool startupOffloading = false;
242
243 if(_config.isSet("offload.startupOffloading"))
244 {
245 _config(startupOffloading, "offload.startupOffloading");
246 }
248
249 return 0;
250}
251
252inline
254{
255 loadConfigImpl(config);
256}
257
258inline
260{
261
262 createStandardIndiNumber<float>( m_indiP_gain, "gain", 0, 1, 0, "%0.2f");
263 m_indiP_gain["current"] = m_gain;
264 m_indiP_gain["target"] = m_gain;
265
267 {
269 return -1;
270 }
271
272
273 createStandardIndiNumber<float>( m_indiP_leak, "leak", 0, 1, 0, "%0.2f");
274 m_indiP_leak["current"] = m_leak;
275 m_indiP_leak["target"] = m_leak;
276
278 {
280 return -1;
281 }
282
283 createStandardIndiNumber<float>( m_indiP_actLim, "actLim", 0, 8, 0, "%0.2f");
284 m_indiP_actLim["current"] = m_actLim;
285 m_indiP_actLim["target"] = m_actLim;
286
288 {
290 return -1;
291 }
292
293 if(prepareModes() < 0 )
294 {
296 return -1;
297 }
298
300 {
301 return log<software_error,-1>({__FILE__, __LINE__});
302 }
303
304 createStandardIndiRequestSw( m_indiP_zero, "zero", "zero loop");
306 {
308 return -1;
309 }
310
311 createStandardIndiNumber<int>( m_indiP_numModes, "numModes", 0, 97, 0, "%d");
312 m_indiP_numModes["current"] = m_numModes;
313 m_indiP_numModes["target"] = m_numModes;
314
316 {
318 return -1;
319 }
320
323 {
325 return -1;
326 }
327
328 REG_INDI_SETPROP(m_indiP_fpsSource, m_fpsSource, std::string("fps"));
329 REG_INDI_SETPROP(m_indiP_navgSource, m_navgSource, std::string("nAverage"));
330
332 m_indiP_fps.add(pcf::IndiElement("current"));
334 {
336 return -1;
337 }
338
340
341 return 0;
342}
343
344inline
346{
347 if( shmimMonitorT::appLogic() < 0)
348 {
349 return log<software_error,-1>({__FILE__,__LINE__});
350 }
351
352
353 std::unique_lock<std::mutex> lock(m_indiMutex);
354
356 {
358 }
359
360
361 return 0;
362}
363
364inline
366{
368
369
370 return 0;
371}
372
373inline
375{
376 if(m_navg < 1)
377 {
378 m_effFPS = 0;
379 }
380 else m_effFPS = m_fps/m_navg;
382
383 std::cerr << "Effective FPS: " << m_effFPS << "\n";
384
385 return 0;
386}
387
388inline
390{
391 static_cast<void>(dummy); //be unused
392
393 //std::unique_lock<std::mutex> lock(m_indiMutex);
394
396
397 /*mx::fits::fitsFile<float> ff;
398 ff.read(m_twRespM, m_twRespMPath);
399
400 std::cerr << "Read a " << m_twRespM.rows() << " x " << m_twRespM.cols() << " matrix.\n";
401 */
402
403 if(m_dmOpened)
404 {
406 }
407
408 m_dmOpened = false;
409 m_dmRestart = false; //Set this up front, since we're about to restart.
410
411 if( ImageStreamIO_openIm(&m_dmStream, m_dmChannel.c_str()) == 0)
412 {
413 if(m_dmStream.md[0].sem < 10)
414 {
416 }
417 else
418 {
419 m_dmOpened = true;
420 }
421 }
422
423 if(!m_dmOpened)
424 {
425 log<software_error>({__FILE__, __LINE__, m_dmChannel + " not opened."});
426 return -1;
427 }
428 else
429 {
430 m_dmWidth = m_dmStream.md->size[0];
431 m_dmHeight = m_dmStream.md->size[1];
432
433 m_dmDataType = m_dmStream.md->datatype;
435
436 log<text_log>( "Opened " + m_dmChannel + " " + std::to_string(m_dmWidth) + " x " + std::to_string(m_dmHeight) + " with data type: " + std::to_string(m_dmDataType));
437
439 m_woofer.setZero();
440 }
441
442 m_modeAmps.resize(1, m_tModesOrtho.planes());
443
444 ///\todo size checks here.
445
446 //state(stateCodes::OPERATING);
447
448 return 0;
449}
450
451inline
452int t2wOffloader::processImage( void * curr_src,
453 const dev::shmimT & dummy
454 )
455{
456 static_cast<void>(dummy); //be unused
457
458 if(!m_offloading) return 0;
459
460 if(m_numModes == 0)
461 {
462 m_wooferDelta = m_twRespM.matrix() * Eigen::Map<Eigen::Matrix<float,-1,-1>>((float *)curr_src, m_width*m_height,1);
463 }
464 else
465 {
466 m_modeAmps = Eigen::Map<Eigen::Matrix<float,-1,-1>>((float *) curr_src, 1, m_width*m_height) * Eigen::Map<Eigen::Matrix<float,-1,-1>>(m_tModesOrtho.data(), m_tModesOrtho.rows()*m_tModesOrtho.cols(), m_tModesOrtho.planes());
467
468 m_wooferDelta = m_modeAmps(0,0) * m_wModes.image(0);
469 for(int p=1; p < m_numModes && p < m_maxModes; ++p)
470 {
471 m_wooferDelta += m_modeAmps(0,p)*m_wModes.image(p);
472 }
473
474
475 }
476
477 while(m_dmStream.md[0].write == 1); //Check if zero() is running
478
479
480 m_woofer = m_gain* Eigen::Map<Eigen::Array<float,-1,-1>>( m_wooferDelta.data(), m_dmWidth, m_dmHeight) + (1.0-m_leak)*m_woofer;
481
482 for(int ii = 0; ii < m_woofer.rows(); ++ii)
483 {
484 for(int jj = 0; jj < m_woofer.cols(); ++jj)
485 {
486 if( fabs(m_woofer(ii,jj)) > m_actLim)
487 {
488 if(m_woofer(ii,jj) > 0) m_woofer(ii,jj) = m_actLim;
489 else m_woofer(ii,jj) = -m_actLim;
490 }
491 }
492 }
493
494 m_dmStream.md[0].write = 1;
495
496 memcpy(m_dmStream.array.raw, m_woofer.data(), m_woofer.rows()*m_woofer.cols()*m_typeSize);
497
498 m_dmStream.md[0].cnt0++;
499
500 m_dmStream.md->write=0;
502
503 return 0;
504}
505
506inline
508{
509
510 //Check if processImage is running
511 while(m_dmStream.md[0].write == 1);
512
513 m_dmStream.md[0].write = 1;
514
515 m_woofer.setZero();
516
517 memcpy(m_dmStream.array.raw, m_woofer.data(), m_woofer.rows()*m_woofer.cols()*m_typeSize);
518
519 m_dmStream.md[0].cnt0++;
520
521 m_dmStream.md->write=0;
523
525
526 return 0;
527
528}
529
531{
532 mx::improc::eigenCube<float> tmodes;
533
534 mx::fits::fitsFile<float> ff;
535
537 std::cerr << "Tweeter modes: " << tmodes.rows() << " x " << tmodes.cols() << " x " << tmodes.planes() << "\n";
538
540 std::cerr << "Tweeter mask: " << m_tweeterMask.rows() << " x " << m_tweeterMask.cols() << "\n";
541
543
544 std::cerr << "t2w Response matrix: " << m_twRespM.rows() << " x " << m_twRespM.cols() << " matrix.\n";
545
546
547 for(int p=0; p < tmodes.planes(); ++p)
548 {
549 tmodes.image(p) *= m_tweeterMask;
550 float norm = (tmodes.image(p)).square().sum();
551 tmodes.image(p) /= sqrt(norm);
552 }
553
554 m_tModesOrtho.resize(tmodes.rows(), tmodes.cols(), m_maxModes);
555
556 for(int p=0;p<m_tModesOrtho.planes();++p)
557 {
558 m_tModesOrtho.image(p) = tmodes.image(p);
559 }
560
561 ff.write("/tmp/tModesOrtho.fits", m_tModesOrtho);
562
563 m_wModes.resize(11,11,m_tModesOrtho.planes());
564 mx::improc::eigenImage<realT> win, wout;
565
566 win.resize(11,11);
567 wout.resize(11,11);
568
569 for(int p=0; p < m_tModesOrtho.planes(); ++p)
570 {
571 win = m_tModesOrtho.image(p);
572 Eigen::Map<Eigen::Matrix<float,-1,-1>>(wout.data(), wout.rows()*wout.cols(),1) = m_twRespM.matrix() * Eigen::Map<Eigen::Matrix<float,-1,-1>>(win.data(), win.rows()*win.cols(),1);
573 m_wModes.image(p) = wout;
574 }
575
576 ff.write("/tmp/wModes.fits", m_wModes);
577
578 return 0;
579
580}
581
582INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_gain)(const pcf::IndiProperty &ipRecv)
583{
584 if(ipRecv.getName() != m_indiP_gain.getName())
585 {
586 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
587 return -1;
588 }
589
590 float target;
591
592 if( indiTargetUpdate( m_indiP_gain, target, ipRecv, true) < 0)
593 {
594 log<software_error>({__FILE__,__LINE__});
595 return -1;
596 }
597
598 m_gain = target;
599
600 updateIfChanged(m_indiP_gain, "current", m_gain);
601 updateIfChanged(m_indiP_gain, "target", m_gain);
602
603 log<text_log>("set gain to " + std::to_string(m_gain), logPrio::LOG_NOTICE);
604
605 return 0;
606}
607
608INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_leak)(const pcf::IndiProperty &ipRecv)
609{
610 if(ipRecv.getName() != m_indiP_leak.getName())
611 {
612 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
613 return -1;
614 }
615
616 float target;
617
618 if( indiTargetUpdate( m_indiP_leak, target, ipRecv, true) < 0)
619 {
620 log<software_error>({__FILE__,__LINE__});
621 return -1;
622 }
623
624 m_leak = target;
625
626 updateIfChanged(m_indiP_leak, "current", m_leak);
627 updateIfChanged(m_indiP_leak, "target", m_leak);
628
629 log<text_log>("set leak to " + std::to_string(m_leak), logPrio::LOG_NOTICE);
630
631 return 0;
632}
633
634INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_actLim)(const pcf::IndiProperty &ipRecv)
635{
636 if(ipRecv.getName() != m_indiP_actLim.getName())
637 {
638 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
639 return -1;
640 }
641
642 float target;
643
644 if( indiTargetUpdate( m_indiP_actLim, target, ipRecv, true) < 0)
645 {
646 log<software_error>({__FILE__,__LINE__});
647 return -1;
648 }
649
650 m_actLim = target;
651
652 updateIfChanged(m_indiP_actLim, "current", m_actLim);
653 updateIfChanged(m_indiP_actLim, "target", m_actLim);
654
655 log<text_log>("set actuator limit to " + std::to_string(m_actLim), logPrio::LOG_NOTICE);
656
657 return 0;
658}
659
660INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_zero)(const pcf::IndiProperty &ipRecv)
661{
662 if(ipRecv.getName() != m_indiP_zero.getName())
663 {
664 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
665 return -1;
666 }
667
668 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
669 {
670 return zero();
671
672 }
673 return 0;
674}
675
676INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_numModes)(const pcf::IndiProperty &ipRecv)
677{
678 if(ipRecv.getName() != m_indiP_numModes.getName())
679 {
680 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
681 return -1;
682 }
683
684 float target;
685
686 if( indiTargetUpdate( m_indiP_numModes, target, ipRecv, true) < 0)
687 {
688 log<software_error>({__FILE__,__LINE__});
689 return -1;
690 }
691
692 m_numModes = target;
693
694 updateIfChanged(m_indiP_numModes, "current", m_numModes);
695 updateIfChanged(m_indiP_numModes, "target", m_numModes);
696
697 log<text_log>("set number of modes to " + std::to_string(m_numModes), logPrio::LOG_NOTICE);
698
699 return 0;
700}
701
702INDI_NEWCALLBACK_DEFN(t2wOffloader, m_indiP_offloadToggle )(const pcf::IndiProperty &ipRecv)
703{
704 if(ipRecv.getName() != m_indiP_offloadToggle.getName())
705 {
706 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
707 return -1;
708 }
709
710 //switch is toggled to on
711 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
712 {
713 if(!m_offloading) //not offloading so change
714 {
715 m_woofer.setZero(); //always zero when offloading starts
716 log<text_log>("zeroed", logPrio::LOG_NOTICE);
717
718 m_offloading = true;
719 log<text_log>("started offloading", logPrio::LOG_NOTICE);
720 updateSwitchIfChanged(m_indiP_offloadToggle, "toggle", pcf::IndiElement::On, INDI_OK);
721 }
722 return 0;
723 }
724
725 //switch is toggle to off
726 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
727 {
728 if(m_offloading) //offloading so change it
729 {
730 m_offloading = false;
731 log<text_log>("stopped offloading", logPrio::LOG_NOTICE);
732 updateSwitchIfChanged(m_indiP_offloadToggle, "toggle", pcf::IndiElement::Off, INDI_IDLE);
733 }
734 return 0;
735 }
736
737 return 0;
738}
739
740INDI_SETCALLBACK_DEFN( t2wOffloader, m_indiP_fpsSource )(const pcf::IndiProperty &ipRecv)
741{
742 if( ipRecv.getName() != m_indiP_fpsSource.getName())
743 {
744 log<software_error>({__FILE__, __LINE__, "Invalid INDI property."});
745 return -1;
746 }
747
748 if( ipRecv.find("current") != true ) //this isn't valie
749 {
750 return 0;
751 }
752
753 std::lock_guard<std::mutex> guard(m_indiMutex);
754
755 realT fps = ipRecv["current"].get<float>();
756
757 if(fps != m_fps)
758 {
759 m_fps = fps;
760 std::cout << "Got fps: " << m_fps << "\n";
761 updateFPS();
762 }
763
764 return 0;
765}
766
767INDI_SETCALLBACK_DEFN( t2wOffloader, m_indiP_navgSource )(const pcf::IndiProperty &ipRecv)
768{
769 if( ipRecv.getName() != m_indiP_navgSource.getName())
770 {
771 log<software_error>({__FILE__, __LINE__, "Invalid INDI property."});
772 return -1;
773 }
774
775 if( ipRecv.find("current") != true ) //this isn't valie
776 {
777 return 0;
778 }
779
780 std::lock_guard<std::mutex> guard(m_indiMutex);
781
782 realT navg = ipRecv["current"].get<float>();
783
784 if(navg != m_navg)
785 {
786 m_navg = navg;
787 std::cout << "Got navg: " << m_navg << "\n";
788 updateFPS();
789 }
790
791 return 0;
792}
793
794} //namespace app
795} //namespace MagAOX
796
797#endif //t2wOffloader_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.
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 createStandardIndiToggleSw(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 toggle element.
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.
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
int appShutdown()
Shuts down the shmimMonitor thread.
uint8_t m_dataType
The ImageStreamIO type code.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
size_t m_typeSize
The size of the type, in bytes. Result of sizeof.
int allocate(const dev::shmimT &dummy)
mx::improc::eigenImage< realT > m_twRespM
mx::improc::eigenImage< realT > m_tweeterMask
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_actLim)
mx::improc::eigenImage< realT > m_tweeter
mx::improc::eigenImage< realT > m_modeAmps
pcf::IndiProperty m_indiP_leak
int processImage(void *curr_src, const dev::shmimT &dummy)
uint32_t m_dmHeight
The height of the image.
~t2wOffloader() noexcept
D'tor, declared and defined for noexcept.
pcf::IndiProperty m_indiP_fps
pcf::IndiProperty m_indiP_fpsSource
pcf::IndiProperty m_indiP_numModes
int m_navg
Current navg from the averager.
virtual int appLogic()
Implementation of the FSM for t2wOffloader.
mx::improc::eigenCube< float > m_tModesOrtho
INDI_SETCALLBACK_DECL(t2wOffloader, m_indiP_navgSource)
std::string m_tweeterModeFile
File containing the tweeter modes to use for offloading.
virtual int appStartup()
Startup function.
float realT
Floating point type in which to do all calculations.
pcf::IndiProperty m_indiP_offloadToggle
pcf::IndiProperty m_indiP_navgSource
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_gain)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
float m_actLim
the upper limit on woofer actuator commands. default is 7.0.
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_leak)
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_offloadToggle)
mx::improc::eigenImage< realT > m_woofer
uint32_t m_dmWidth
The width of the image.
mx::improc::eigenImage< realT > m_wooferDelta
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_zero)
INDI_SETCALLBACK_DECL(t2wOffloader, m_indiP_fpsSource)
float m_fps
Current FPS from the FPS source.
dev::shmimMonitor< t2wOffloader > shmimMonitorT
virtual int appShutdown()
Shutdown the app.
INDI_NEWCALLBACK_DECL(t2wOffloader, m_indiP_numModes)
pcf::IndiProperty m_indiP_gain
uint8_t m_dmDataType
The ImageStreamIO type code.
pcf::IndiProperty m_indiP_actLim
mx::improc::eigenCube< float > m_wModes
size_t m_dmTypeSize
The size of the type, in bytes.
pcf::IndiProperty m_indiP_zero
#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.
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
#define INDI_IDLE
Definition indiUtils.hpp:28
#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.
Software ERR log entry.