API
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 
20 namespace MagAOX
21 {
22 namespace 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  */
43 class 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 
57 protected:
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 
100  IMAGE m_dmStream;
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 
112 public:
113  /// Default c'tor.
114  t2wOffloader();
115 
116  /// D'tor, declared and defined for noexcept.
117  ~t2wOffloader() noexcept
118  {}
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 
161 protected:
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 
194 inline
195 t2wOffloader::t2wOffloader() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
196 {
197  return;
198 }
199 
200 inline
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 
222 inline
223 int t2wOffloader::loadConfigImpl( mx::app::appConfigurator & _config )
224 {
225 
226  shmimMonitorT::loadConfig(_config);
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  }
247  m_offloading = startupOffloading;
248 
249  return 0;
250 }
251 
252 inline
254 {
255  loadConfigImpl(config);
256 }
257 
258 inline
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  {
268  log<software_error>({__FILE__,__LINE__});
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  {
279  log<software_error>({__FILE__,__LINE__});
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  {
289  log<software_error>({__FILE__,__LINE__});
290  return -1;
291  }
292 
293  if(prepareModes() < 0 )
294  {
295  log<software_error>({__FILE__,__LINE__});
296  return -1;
297  }
298 
299  if(shmimMonitorT::appStartup() < 0)
300  {
301  return log<software_error,-1>({__FILE__, __LINE__});
302  }
303 
304  createStandardIndiRequestSw( m_indiP_zero, "zero", "zero loop");
306  {
307  log<software_error>({__FILE__,__LINE__});
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  {
317  log<software_error>({__FILE__,__LINE__});
318  return -1;
319  }
320 
323  {
324  log<software_error>({__FILE__,__LINE__});
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  {
335  log<software_error>({__FILE__,__LINE__});
336  return -1;
337  }
338 
340 
341  return 0;
342 }
343 
344 inline
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 
355  if(shmimMonitorT::updateINDI() < 0)
356  {
357  log<software_error>({__FILE__, __LINE__});
358  }
359 
360 
361  return 0;
362 }
363 
364 inline
366 {
368 
369 
370  return 0;
371 }
372 
373 inline
375 {
376  if(m_navg < 1)
377  {
378  m_effFPS = 0;
379  }
380  else m_effFPS = m_fps/m_navg;
381  updateIfChanged(m_indiP_fps, "current", m_effFPS);
382 
383  std::cerr << "Effective FPS: " << m_effFPS << "\n";
384 
385  return 0;
386 }
387 
388 inline
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  {
405  ImageStreamIO_closeIm(&m_dmStream);
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  {
415  ImageStreamIO_closeIm(&m_dmStream);
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;
434  m_dmTypeSize = ImageStreamIO_typesize(m_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 
438  m_woofer.resize(m_dmWidth, m_dmHeight);
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 
451 inline
452 int 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;
501  ImageStreamIO_sempost(&m_dmStream,-1);
502 
503  return 0;
504 }
505 
506 inline
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;
522  ImageStreamIO_sempost(&m_dmStream,-1);
523 
524  log<text_log>("zeroed", logPrio::LOG_NOTICE);
525 
526  return 0;
527 
528 }
529 
531 {
532  mx::improc::eigenCube<float> tmodes;
533 
534  mx::fits::fitsFile<float> ff;
535 
536  ff.read(tmodes, m_tweeterModeFile);
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 
542  ff.read(m_twRespM, m_twRespMPath);
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 
582 INDI_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 
608 INDI_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 
634 INDI_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 
660 INDI_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 
676 INDI_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 
702 INDI_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 
740 INDI_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 
767 INDI_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.
Definition: MagAOXApp.hpp:3120
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.
Definition: MagAOXApp.hpp:2573
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2297
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.
Definition: MagAOXApp.hpp:2543
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1804
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
Definition: MagAOXApp.hpp:2517
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
Definition: MagAOXApp.hpp:2655
std::mutex m_indiMutex
Mutex for locking INDI communications.
Definition: MagAOXApp.hpp:545
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)
t2wOffloader()
Default c'tor.
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.
friend class t2wOffloader_test
~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(prop)
Get the name of the static callback wrapper for a new property.
Definition: indiMacros.hpp:208
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
Definition: indiMacros.hpp:282
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:55
#define INDI_IDLE
Definition: indiUtils.hpp:28
#define INDI_OK
Definition: indiUtils.hpp:29
std::ostream & cerr()
std::ostream & cout()
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
Definition: indiUtils.hpp:212
const pcf::IndiProperty & ipRecv
Definition: MagAOXApp.hpp:3434
INDI_SETCALLBACK_DEFN(adcTracker, m_indiP_teldata)(const pcf
Definition: adcTracker.hpp:461
updateIfChanged(m_indiP_angle, "target", m_angle)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition: dm.hpp:24
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
Definition: logPriority.hpp:46
Software ERR log entry.