API
psfFit.hpp
Go to the documentation of this file.
1 /** \file psfFit.hpp
2  * \brief The MagAO-X PSF Fitter application header
3  *
4  * \ingroup psfFit_files
5  */
6 
7 #ifndef psfFit_hpp
8 #define psfFit_hpp
9 
10 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
11 #include "../../magaox_git_version.h"
12 
13 /** \defgroup psfFit
14  * \brief The MagAO-X PSF fitter.
15  *
16  * <a href="../handbook/operating/software/apps/psfFit.html">Application Documentation</a>
17  *
18  * \ingroup apps
19  *
20  */
21 
22 /** \defgroup psfFit_files
23  * \ingroup psfFit
24  */
25 
26 namespace MagAOX
27 {
28 namespace app
29 {
30 
31 struct darkShmimT
32 {
33  static std::string configSection()
34  {
35  return "darkShmim";
36  };
37 
38  static std::string indiPrefix()
39  {
40  return "dark";
41  };
42 };
43 
44 struct refShmimT
45 {
46  static std::string configSection()
47  {
48  return "refShmim";
49  };
50 
51  static std::string indiPrefix()
52  {
53  return "ref";
54  };
55 };
56 
57 /// The MagAO-X PSF Fitter
58 /**
59  * \ingroup psfFit
60  */
61 class psfFit : public MagAOXApp<true>,
62  public dev::shmimMonitor<psfFit>,
63  public dev::shmimMonitor<psfFit, darkShmimT>,
64  public dev::shmimMonitor<psfFit, refShmimT>,
65  public dev::frameGrabber<psfFit>,
66  public dev::telemeter<psfFit>
67 {
68  // Give the test harness access.
69  friend class psfFit_test;
70 
71  friend class dev::shmimMonitor<psfFit>;
72  friend class dev::shmimMonitor<psfFit, darkShmimT>;
73  friend class dev::shmimMonitor<psfFit, refShmimT>;
74  friend class dev::frameGrabber<psfFit>;
75 
76  friend class dev::telemeter<psfFit>;
77 
78  public:
79  /// The base shmimMonitor type
81 
82  /// The dark shmimMonitor type
84 
85  /// The reference shmimMonitor type
87 
88  // The base frameGrabber type
90 
91  // The base telemeter type
93 
94  /// Floating point type in which to do all calculations.
95  typedef float realT;
96 
97  /** \name app::dev Configurations
98  *@{
99  */
100 
101  static constexpr bool c_frameGrabber_flippable =
102  false; ///< app:dev config to tell framegrabber these images can not be flipped
103 
104  ///@}
105 
106  protected:
107  /** \name Configurable Parameters
108  *@{
109  */
110 
111  std::string m_fpsSource; ///< Device name for getting fps if time-based averaging is used. This device should have
112  ///< *.fps.current.
113 
114  uint16_t m_fitCircBuffMaxLength{ 5 * 10000 }; ///< Maximum length of the latency measurement circular buffers
115 
116  float m_fitCircBuffMaxTime{ 5 }; ///< Maximum time of the latency meaurement circular buffers
117 
118  float m_deltaPixThresh{ 2 }; /**< Threshold in pixels for skipping frame due to mismatch between max and c.o.l.
119  Default 2.*/
120 
121  float m_sigmaMaxThreshUp{ 5 }; /**< Threshold in rms for skipping frame due to max positive difference from mean
122  max. Default 5.*/
123 
124  float m_sigmaMaxThreshDown{ 5 }; /**< Threshold in rms for skipping frame due to max negative difference from mean
125  mas. Default 5.*/
126 
127  float m_sigmaPixThresh{ 10 }; /**< Threshold in rms for skipping frame due to max difference from last value.
128  Example: if this is set to 10, then the pixel postion has to change from -5 sigma
129  to + 5 sigma to be rejected. Default 10.*/
130 
131  ///@}
132 
133  mx::improc::eigenImage<float> m_image; ///< Holds the raw image
134 
135  mx::improc::eigenImage<float> m_dark; ///< Holds the dark image
136 
137  mx::improc::eigenImage<float> m_ref; ///< Holds the reference image
138 
139  bool m_updated{ false }; ///< Indicates that the coordinates were updated was updated
140 
141  bool m_skipped{ false }; ///< Indicates that the image failed quality control and this is a skip frame
142 
143  float m_x{ 0 }; ///< The current x coordinate
144  float m_last_x{ 0 }; ///< The previous x coordinate
145 
146  float m_y{ 0 }; ///< The current y coordinate
147  float m_last_y{ 0 }; ///< The previous y coordinate
148 
149  float m_dx{ 0 }; ///< The offset in x to apply to non-skipped measurements
150  float m_dy{ 0 }; ///< The offset in y to apply to non-skipped measurements
151 
152  float m_fps{ 0 }; ///< The frame rate from the source camera
153 
154  mx::sigproc::circularBufferIndex<float, cbIndexT> m_pcb; ///< Circular buffer for max pixel (p=peak)
155  mx::sigproc::circularBufferIndex<float, cbIndexT> m_xcb; ///< Circular buffer for x COL coords
156  mx::sigproc::circularBufferIndex<float, cbIndexT> m_ycb; ///< Circular buffer for y COL coords
157 
158  std::vector<float> m_pcbD; ///< Vector for doing calcs on max pixel
159  std::vector<float> m_xcbD; ///< Vector for doing calcs on x COL coords
160  std::vector<float> m_ycbD; ///< Vector for doing calcs on y COL coords
161 
162  float m_mnp{ 0 }; ///< The mean max pixel over the stats time
163  float m_rmsp{ 0 }; ///< The rms max pixel over the stats time
164 
165  float m_mnx{ 0 }; ///< The mean x coord over the stats time
166  float m_rmsx{ 0 }; ///< The rms x coord over the stats time
167  float m_mny{ 0 }; ///< The mean y coord over the stats time
168  float m_rmsy{ 0 }; ///< The rms y coord over the stats time
169 
170  public:
171  /// Default c'tor.
172  psfFit();
173 
174  /// D'tor, declared and defined for noexcept.
175  ~psfFit() noexcept;
176 
177  virtual void setupConfig();
178 
179  /// Implementation of loadConfig logic, separated for testing.
180  /** This is called by loadConfig().
181  */
182  int loadConfigImpl(
183  mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
184 
185  virtual void loadConfig();
186 
187  /// Startup function
188  /**
189  *
190  */
191  virtual int appStartup();
192 
193  /// Implementation of the FSM for psfFit.
194  /**
195  * \returns 0 on no critical error
196  * \returns -1 on an error requiring shutdown
197  */
198  virtual int appLogic();
199 
200  /// Shutdown the app.
201  /**
202  *
203  */
204  virtual int appShutdown();
205 
206  // shmimMonitor interface:
207  int allocate( const dev::shmimT & );
208 
209  int processImage( void *curr_src, const dev::shmimT & );
210 
211  // shmimMonitor interface for dark:
212  int allocate( const darkShmimT & );
213 
214  int processImage( void *curr_src, const darkShmimT & );
215 
216  // shmimMonitor interface for reference:
217  int allocate( const refShmimT & );
218 
219  int processImage( void *curr_src, const refShmimT & );
220 
221  protected:
222  std::mutex m_imageMutex;
223 
224  sem_t m_smSemaphore{ 0 }; ///< Semaphore used to synchronize the fg thread and the sm thread.
225 
226  public:
227  /** \name dev::frameGrabber interface
228  *
229  * @{
230  */
231 
232  /// Implementation of the framegrabber configureAcquisition interface
233  /**
234  * \returns 0 on success
235  * \returns -1 on error
236  */
237  int configureAcquisition();
238 
239  /// Implementation of the framegrabber fps interface
240  /**
241  * \todo this needs to infer the stream fps and return it
242  */
243  float fps()
244  {
245  return m_fps;
246  }
247 
248  /// Implementation of the framegrabber startAcquisition interface
249  /**
250  * \returns 0 on success
251  * \returns -1 on error
252  */
253  int startAcquisition();
254 
255  /// Implementation of the framegrabber acquireAndCheckValid interface
256  /**
257  * \returns 0 on success
258  * \returns -1 on error
259  */
260  int acquireAndCheckValid();
261 
262  /// Implementation of the framegrabber loadImageIntoStream interface
263  /**
264  * \returns 0 on success
265  * \returns -1 on error
266  */
267  int loadImageIntoStream( void *dest /**< [in] */ );
268 
269  /// Implementation of the framegrabber reconfig interface
270  /**
271  * \returns 0 on success
272  * \returns -1 on error
273  */
274  int reconfig();
275 
276  ///@}
277 
278  protected:
279  /** \name INDI
280  * @{
281  */
282 
283  pcf::IndiProperty m_indiP_values;
284 
285  pcf::IndiProperty m_indiP_reset;
287 
288  pcf::IndiProperty m_indiP_statsTime;
290 
291  pcf::IndiProperty m_indiP_deltaPixThresh;
293 
294  pcf::IndiProperty m_indiP_sigmaMaxThreshUp;
296 
297  pcf::IndiProperty m_indiP_sigmaMaxThreshDown;
299 
300  pcf::IndiProperty m_indiP_sigmaPixThresh;
302 
303  pcf::IndiProperty m_indiP_dx;
305 
306  pcf::IndiProperty m_indiP_dy;
308 
309  pcf::IndiProperty m_indiP_fpsSource;
311 
312  ///@}
313 
314  /** \name Telemeter Interface
315  *
316  * @{
317  */
318  int checkRecordTimes();
319 
320  int recordTelem( const telem_fgtimings * );
321 
322  ///@}
323 };
324 
325 inline psfFit::psfFit() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
326 {
329 
330  return;
331 }
332 
333 inline psfFit::~psfFit() noexcept
334 {
335 }
336 
337 inline void psfFit::setupConfig()
338 {
339  SHMIMMONITOR_SETUP_CONFIG( config );
342  FRAMEGRABBER_SETUP_CONFIG( config );
343  TELEMETER_SETUP_CONFIG( config );
344 
345  config.add(
346  "fitter.fpsSource",
347  "",
348  "fitter.fpsSource",
349  argType::Required,
350  "fitter",
351  "fpsSource",
352  false,
353  "string",
354  "Device name for getting fps if time-based averaging is used. This device should have *.fps.current." );
355 
356  config.add( "fitter.deltaPixThresh",
357  "",
358  "fitter.deltaPixThresh",
359  argType::Required,
360  "fitter",
361  "deltaPixThresh",
362  false,
363  "float",
364  "Threshold in pixels for skipping frame due to mismatch between max and c.o.l. Default 2." );
365  config.add( "fitter.sigmaMaxThreshUp",
366  "",
367  "fitter.sigmaMaxThreshUp",
368  argType::Required,
369  "fitter",
370  "sigmaMaxThreshUp",
371  false,
372  "float",
373  "Threshold in rms for skipping frame due to max positive difference from mean max. Default 5." );
374  config.add( "fitter.sigmaMaxThreshDown",
375  "",
376  "fitter.sigmaMaxThreshDown",
377  argType::Required,
378  "fitter",
379  "sigmaMaxThreshDown",
380  false,
381  "float",
382  "Threshold in rms for skipping frame due to max negative difference from mean max. Default 5." );
383 
384  config.add( "fitter.sigmaPixThresh",
385  "",
386  "fitter.sigmaPixThresh",
387  argType::Required,
388  "fitter",
389  "sigmaPixThresh",
390  false,
391  "float",
392  "Threshold in rms for skipping frame due to max difference from last value. Example: if this is set "
393  "to 10, then the pixel postion has to change from -5 sigma to + 5 sigma to be rejected. Default 10." );
394 }
395 
396 inline int psfFit::loadConfigImpl( mx::app::appConfigurator &_config )
397 {
398  SHMIMMONITOR_LOAD_CONFIG( _config );
401 
402  FRAMEGRABBER_LOAD_CONFIG( _config );
403  TELEMETER_LOAD_CONFIG( _config );
404 
405  _config( m_fpsSource, "fitter.fpsSource" );
406  _config( m_deltaPixThresh, "fitter.deltaPixThresh" );
407  _config( m_sigmaMaxThreshUp, "fitter.sigmaMaxThreshUp" );
408  _config( m_sigmaMaxThreshDown, "fitter.sigmaMaxThreshDown" );
409  _config( m_sigmaPixThresh, "fitter.sigmaPixThresh" );
410 
411  return 0;
412 }
413 
414 inline void psfFit::loadConfig()
415 {
416  loadConfigImpl( config );
417 }
418 
419 inline int psfFit::appStartup()
420 {
424 
425  if( sem_init( &m_smSemaphore, 0, 0 ) < 0 )
426  {
427  log<software_critical>( { __FILE__, __LINE__, errno, 0, "Initializing S.M. semaphore" } );
428  return -1;
429  }
430 
433 
434  if( m_fpsSource != "" )
435  {
436  REG_INDI_SETPROP( m_indiP_fpsSource, m_fpsSource, std::string( "fps" ) );
437  }
438 
439  CREATE_REG_INDI_RO_NUMBER( m_indiP_values, "values", "", "" );
440  m_indiP_values.add( pcf::IndiElement( "max_mean" ) );
441  m_indiP_values.add( pcf::IndiElement( "max_rms" ) );
442  m_indiP_values.add( pcf::IndiElement( "x_mean" ) );
443  m_indiP_values.add( pcf::IndiElement( "x_rms" ) );
444  m_indiP_values.add( pcf::IndiElement( "y_mean" ) );
445  m_indiP_values.add( pcf::IndiElement( "y_rms" ) );
446 
448 
449  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_statsTime, "statsTime", 0, 5, 1, "%0.1f", "", "" );
450  m_indiP_statsTime["current"].setValue( m_fitCircBuffMaxTime );
451  m_indiP_statsTime["target"].setValue( m_fitCircBuffMaxTime );
452 
453  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_deltaPixThresh, "deltaPixThresh", 0, 512, 1, "%0.1f", "", "" );
454  m_indiP_deltaPixThresh["current"].setValue( m_deltaPixThresh );
455  m_indiP_deltaPixThresh["target"].setValue( m_deltaPixThresh );
456 
457  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaMaxThreshUp, "sigmaMaxThreshUp", 0, 512, 1, "%0.1f", "", "" );
458  m_indiP_sigmaMaxThreshUp["current"].setValue( m_sigmaMaxThreshUp );
459  m_indiP_sigmaMaxThreshUp["target"].setValue( m_sigmaMaxThreshUp );
460 
461  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaMaxThreshDown, "sigmaMaxThreshDown", 0, 512, 1, "%0.1f", "", "" );
462  m_indiP_sigmaMaxThreshDown["current"].setValue( m_sigmaMaxThreshDown );
463  m_indiP_sigmaMaxThreshDown["target"].setValue( m_sigmaMaxThreshDown );
464 
465  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaPixThresh, "sigmaPixThresh", 0, 512, 1, "%0.1f", "", "" );
466  m_indiP_sigmaPixThresh["current"].setValue( m_sigmaPixThresh );
467  m_indiP_sigmaPixThresh["target"].setValue( m_sigmaPixThresh );
468 
469  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dx, "dx", -100, 100, 1e-2, "%0.02f", "", "" );
470  m_indiP_dx["current"].setValue( m_dx );
471  m_indiP_dx["target"].setValue( m_dx );
472 
473  CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dy, "dy", -100, 100, 1e-2, "%0.02f", "", "" );
474  m_indiP_dy["current"].setValue( m_dy );
475  m_indiP_dy["target"].setValue( m_dy );
476 
478 
479  return 0;
480 }
481 
482 inline int psfFit::appLogic()
483 {
489 
490  if( state() == stateCodes::OPERATING && m_xcb.size() > 0 )
491  {
492  if( m_xcb.size() >= m_xcb.maxEntries() )
493  {
494  cbIndexT refEntry = m_xcb.earliest();
495 
496  m_pcbD.resize( m_pcb.maxEntries() - 1 );
497  m_xcbD.resize( m_xcb.maxEntries() - 1 );
498  m_ycbD.resize( m_xcb.maxEntries() - 1 );
499 
500  for( size_t n = 0; n < m_xcb.size(); ++n )
501  {
502  m_pcbD[n] = m_pcb.at( refEntry, n );
503  m_xcbD[n] = m_xcb.at( refEntry, n );
504  m_ycbD[n] = m_ycb.at( refEntry, n );
505  }
506 
507  m_mnp = mx::math::vectorMean( m_pcbD );
508  m_rmsp = sqrt( mx::math::vectorVariance( m_pcbD, m_mnp ) );
509 
510  m_mnx = mx::math::vectorMean( m_xcbD );
511 
512  m_rmsx = sqrt( mx::math::vectorVariance( m_xcbD, m_mnx ) );
513 
514  m_mny = mx::math::vectorMean( m_ycbD );
515  m_rmsy = sqrt( mx::math::vectorVariance( m_ycbD, m_mny ) );
516  }
517  else
518  {
519  m_mnp = 0;
520  m_rmsp = 0;
521 
522  m_mnx = 0;
523  m_rmsx = 0;
524 
525  m_mny = 0;
526  m_rmsy = 0;
527  }
528  }
529  else
530  {
531  m_mnp = 0;
532  m_rmsp = 0;
533 
534  m_mnx = 0;
535  m_rmsx = 0;
536 
537  m_mny = 0;
538  m_rmsy = 0;
539  }
540 
544 
546 
548 
550  std::vector<std::string>( { "max_mean", "max_rms", "x_mean", "x_rms", "y_mean", "y_rms" } ),
551  std::vector<float>( { m_mnp, m_rmsp, m_mnx, m_rmsx, m_mny, m_rmsy } ) );
552 
553  updateIfChanged( m_indiP_dx, "current", m_dx );
554  updateIfChanged( m_indiP_dy, "current", m_dy );
555 
556  return 0;
557 }
558 
560 {
566 
567  return 0;
568 }
569 
570 inline int psfFit::allocate( const dev::shmimT &dummy )
571 {
572  static_cast<void>( dummy );
573 
574  std::lock_guard<std::mutex> guard( m_imageMutex );
575 
577  m_image.setZero();
578 
579  if( m_fitCircBuffMaxLength == 0 || m_fitCircBuffMaxTime == 0 || m_fps <= 0 )
580  {
581  m_pcb.maxEntries( 0 );
582  m_xcb.maxEntries( 0 );
583  m_ycb.maxEntries( 0 );
584 
585  m_mnp = 0;
586  m_rmsp = 0;
587 
588  m_mnx = 0;
589  m_rmsx = 0;
590 
591  m_mny = 0;
592  m_rmsy = 0;
593  }
594  else
595  {
596  // Set up the fit circ. buffs
598  if( cbSz > m_fitCircBuffMaxLength )
599  cbSz = m_fitCircBuffMaxLength;
600  if( cbSz < 3 )
601  cbSz = 3; // Make variance meaningful
602 
603  m_pcb.maxEntries( cbSz );
604  m_xcb.maxEntries( cbSz );
605  m_ycb.maxEntries( cbSz );
606 
607  m_mnp = 0;
608  m_rmsp = 0;
609 
610  m_mnx = 0;
611  m_rmsx = 0;
612 
613  m_mny = 0;
614  m_rmsy = 0;
615  }
616 
617  m_updated = false;
618  return 0;
619 }
620 
621 inline int psfFit::processImage( void *curr_src, const dev::shmimT &dummy )
622 {
623  static_cast<void>( dummy );
624 
625  // counters for managing printing of delta-pix skips when shutter closed
626  static int skip_interval = 10;
627  static int last_passed = skip_interval + 1;
628 
629  std::unique_lock<std::mutex> lock( m_imageMutex );
630 
631  if( m_dark.rows() == m_image.rows() && m_dark.cols() == m_image.cols() )
632  {
633  if( shmimMonitorT::m_dataType == _DATATYPE_UINT16 )
634  {
635  for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
636  {
637  m_image.data()[nn] = ( (uint16_t *)curr_src )[nn] - m_dark.data()[nn];
638  }
639  }
640  else if( shmimMonitorT::m_dataType == _DATATYPE_FLOAT )
641  {
642  for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
643  {
644  m_image.data()[nn] = ( (float *)curr_src )[nn] - m_dark.data()[nn];
645  }
646  }
647  }
648  else
649  {
650  if( shmimMonitorT::m_dataType == _DATATYPE_UINT16 )
651  {
652  for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
653  {
654  m_image.data()[nn] = ( (uint16_t *)curr_src )[nn];
655  }
656  }
657  else if( shmimMonitorT::m_dataType == _DATATYPE_FLOAT )
658  {
659  for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
660  {
661  m_image.data()[nn] = ( (float *)curr_src )[nn];
662  }
663  }
664  }
665 
666  lock.unlock();
667 
668  float max;
669  int x = 0;
670  int y = 0;
671 
672  max = m_image.maxCoeff( &x, &y );
673 
674  mx::improc::imageCenterOfLight( m_x, m_y, m_image );
675 
676  m_skipped = false;
677 
678  if( fabs( m_x - x ) > m_deltaPixThresh || fabs( m_y - y ) > m_deltaPixThresh )
679  {
680  if( last_passed > skip_interval ) // We only print if it's passed skip_interval times in between without failing
681  {
682  std::cerr << "skip frame (delta from max) " << m_x << " " << x << " " << m_y << " " << y << "("
683  << ( m_x - x ) << " " << ( m_y - y ) << ")\n";
684  }
685  last_passed = 0; // if we fail this threshold, we set last_pass to 0 to start over.
686  m_skipped = true;
687 
688  // We do not add these measurements to stats b/c this means bad PSF
689  }
690  else if( last_passed < skip_interval + 1 ) // increment but don't overflow
691  {
692  ++last_passed;
693  }
694 
695  // still filling circular buffer
696  if( ( m_rmsx == 0 || m_rmsy == 0 || m_rmsp == 0 ) && !m_skipped )
697  {
698  if( m_xcb.maxEntries() > 0 )
699  {
700  m_pcb.nextEntry( max );
701  m_xcb.nextEntry( m_x );
702  m_ycb.nextEntry( m_y );
703  }
704 
705  m_last_x = m_x;
706  m_last_y = m_y;
707 
708  m_skipped = true;
709  }
710 
711  // The remaining checks are for wild motions but otherwise valid fits (good PSF)
712 
713  if( ( ( max - m_mnp ) / m_rmsp > m_sigmaMaxThreshUp ) && !m_skipped )
714  {
715  if( m_pcb.maxEntries() > 0 )
716  {
717  m_pcb.nextEntry( max );
718  m_xcb.nextEntry( m_x );
719  m_ycb.nextEntry( m_y );
720  }
721 
722  std::cerr << "skip frame (max-rms up) " << max << " " << m_mnp << " " << m_rmsp << " ("
723  << ( max - m_mnp ) / m_rmsp << ")\n";
724 
725  m_last_x = m_x;
726  m_last_y = m_y;
727 
728  m_skipped = true;
729  }
730 
731  if( ( ( max - m_mnp ) / m_rmsp < -m_sigmaMaxThreshDown ) && !m_skipped )
732  {
733  if( m_pcb.maxEntries() > 0 )
734  {
735  m_pcb.nextEntry( max );
736  m_xcb.nextEntry( m_x );
737  m_ycb.nextEntry( m_y );
738  }
739 
740  std::cerr << "skip frame (max-rms down) " << max << " " << m_mnp << " " << m_rmsp << " ("
741  << ( max - m_mnp ) / m_rmsp << ")\n";
742 
743  m_last_x = m_x;
744  m_last_y = m_y;
745 
746  m_skipped = true;
747  }
748 
749  if( ( fabs( m_x - m_last_x ) / m_rmsx > m_sigmaPixThresh ) && !m_skipped )
750  {
751  if( m_xcb.maxEntries() > 0 )
752  {
753  m_pcb.nextEntry( max );
754  m_xcb.nextEntry( m_x );
755  m_ycb.nextEntry( m_y );
756  }
757 
758  std::cerr << "skip frame (x-rms) " << m_x << " " << m_last_x << " " << m_rmsx << " ("
759  << ( m_x - m_last_x ) / m_rmsx << ")\n";
760 
761  m_last_x = m_x;
762  m_last_y = m_y;
763 
764  m_skipped = true;
765  }
766 
767  if( ( fabs( m_y - m_last_y ) / m_rmsy > m_sigmaPixThresh ) && !m_skipped )
768  {
769  if( m_ycb.maxEntries() > 0 )
770  {
771  m_pcb.nextEntry( max );
772  m_xcb.nextEntry( m_x );
773  m_ycb.nextEntry( m_y );
774  }
775 
776  std::cerr << "skip frame (y-rms) " << m_y << " " << m_last_y << " " << m_rmsy << " ("
777  << ( m_y - m_last_y ) / m_rmsy << ")\n";
778 
779  m_last_x = m_x;
780  m_last_y = m_y;
781 
782  m_skipped = true;
783  }
784 
785  if( m_skipped )
786  {
787  if( m_ref.rows() == 2 && m_ref.cols() == 1 )
788  {
789  m_x = m_ref( 0, 0 );
790  m_y = m_ref( 1, 0 );
791  }
792  else
793  {
794  m_x = 0;
795  m_y = 0;
796  }
797  }
798 
799  m_updated = true;
800 
801  // signal framegrabber
802  // Now tell the f.g. to get going
803  if( sem_post( &m_smSemaphore ) < 0 )
804  {
805  log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to semaphore" } );
806  return -1;
807  }
808 
809  if( !m_skipped )
810  {
811  if( m_xcb.maxEntries() > 0 )
812  {
813  m_pcb.nextEntry( max );
814  m_xcb.nextEntry( m_x );
815  m_ycb.nextEntry( m_y );
816  }
817 
818  m_last_x = m_x;
819  m_last_y = m_y;
820  }
821 
822  return 0;
823 }
824 
825 int psfFit::allocate( const darkShmimT &dummy )
826 {
827  static_cast<void>( dummy );
828 
829  std::lock_guard<std::mutex> guard( m_imageMutex );
830 
832  {
833  return log<software_error, -1>( { __FILE__, __LINE__, "dark is not float" } );
834  }
835 
837  m_dark.setZero();
838 
839  return 0;
840 }
841 
842 int psfFit::processImage( void *curr_src, const darkShmimT &dummy )
843 {
844  static_cast<void>( dummy );
845 
846  std::unique_lock<std::mutex> lock( m_imageMutex );
847 
848  for( unsigned nn = 0; nn < darkShmimMonitorT::m_width * darkShmimMonitorT::m_height; ++nn )
849  {
850  m_dark.data()[nn] = ( (float *)curr_src )[nn];
851  }
852 
853  lock.unlock();
854 
855  log<text_log>( "dark updated", logPrio::LOG_INFO );
856 
857  return 0;
858 }
859 
860 int psfFit::allocate( const refShmimT &dummy )
861 {
862  static_cast<void>( dummy );
863 
864  std::lock_guard<std::mutex> guard( m_imageMutex );
865 
867  {
868  return log<software_error, -1>( { __FILE__, __LINE__, "ref is not float" } );
869  }
870 
872  m_ref.setZero();
873 
874  return 0;
875 }
876 
877 int psfFit::processImage( void *curr_src, const refShmimT &dummy )
878 {
879  static_cast<void>( dummy );
880 
881  std::unique_lock<std::mutex> lock( m_imageMutex );
882 
883  for( unsigned nn = 0; nn < refShmimMonitorT::m_width * refShmimMonitorT::m_height; ++nn )
884  {
885  m_ref.data()[nn] = ( (float *)curr_src )[nn];
886  }
887 
888  lock.unlock();
889 
890  log<text_log>( "reference updated", logPrio::LOG_INFO );
891 
892  return 0;
893 }
894 
896 {
897 
900  frameGrabberT::m_dataType = _DATATYPE_FLOAT;
901 
902  return 0;
903 }
904 
906 {
907  return 0;
908 }
909 
911 {
912  timespec ts;
913 
914  if( clock_gettime( CLOCK_REALTIME, &ts ) < 0 )
915  {
916  log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
917  return -1;
918  }
919 
920  ts.tv_sec += 1;
921 
922  if( sem_timedwait( &m_smSemaphore, &ts ) == 0 )
923  {
924  if( m_updated )
925  {
926  clock_gettime( CLOCK_REALTIME, &m_currImageTimestamp );
927  return 0;
928  }
929  else
930  {
931  return 1;
932  }
933  }
934  else
935  {
936  return 1;
937  }
938 }
939 
940 inline int psfFit::loadImageIntoStream( void *dest )
941 {
942  if( !m_skipped )
943  {
944  ( (float *)dest )[0] = m_x - m_dx;
945  ( (float *)dest )[1] = m_y - m_dy;
946  }
947  else
948  {
949  ( (float *)dest )[0] = m_x;
950  ( (float *)dest )[1] = m_y;
951  }
952 
953  m_updated = false;
954 
955  return 0;
956 }
957 
958 inline int psfFit::reconfig()
959 {
960  return 0;
961 }
962 
963 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_reset )( const pcf::IndiProperty &ipRecv )
964 {
965  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_reset, ipRecv );
966 
967  if( ipRecv.find( "request" ) != true ) // this isn't valid
968  {
969  return -1;
970  }
971 
972  if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
973  {
974  log<text_log>( "reset requested", logPrio::LOG_NOTICE );
975  shmimMonitorT::m_restart = true;
976  }
977 
978  return 0;
979 }
980 
981 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_statsTime )( const pcf::IndiProperty &ipRecv )
982 {
983  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_statsTime, ipRecv );
984 
985  float target;
986 
987  if( indiTargetUpdate( m_indiP_statsTime, target, ipRecv, true ) < 0 )
988  {
989  log<software_error>( { __FILE__, __LINE__ } );
990  return -1;
991  }
992 
993  m_fitCircBuffMaxTime = target;
994 
995  shmimMonitorT::m_restart = true;
996 
997  log<text_log>( "set statsTime = " + std::to_string( m_fitCircBuffMaxTime ), logPrio::LOG_NOTICE );
998 
999  return 0;
1000 }
1001 
1002 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_deltaPixThresh )( const pcf::IndiProperty &ipRecv )
1003 {
1004  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_deltaPixThresh, ipRecv );
1005 
1006  float target;
1007 
1008  if( indiTargetUpdate( m_indiP_deltaPixThresh, target, ipRecv, true ) < 0 )
1009  {
1010  log<software_error>( { __FILE__, __LINE__ } );
1011  return -1;
1012  }
1013 
1014  m_deltaPixThresh = target;
1015 
1016  log<text_log>( "set deltaPixThresh = " + std::to_string( m_deltaPixThresh ), logPrio::LOG_NOTICE );
1017  return 0;
1018 }
1019 
1020 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaMaxThreshUp )( const pcf::IndiProperty &ipRecv )
1021 {
1022  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaMaxThreshUp, ipRecv );
1023 
1024  float target;
1025 
1026  if( indiTargetUpdate( m_indiP_sigmaMaxThreshUp, target, ipRecv, true ) < 0 )
1027  {
1028  log<software_error>( { __FILE__, __LINE__ } );
1029  return -1;
1030  }
1031 
1032  m_sigmaMaxThreshUp = target;
1033 
1034  log<text_log>( "set sigmaMaxThreshUp = " + std::to_string( m_sigmaMaxThreshUp ), logPrio::LOG_NOTICE );
1035  return 0;
1036 }
1037 
1038 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaMaxThreshDown )( const pcf::IndiProperty &ipRecv )
1039 {
1040  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaMaxThreshDown, ipRecv );
1041 
1042  float target;
1043 
1044  if( indiTargetUpdate( m_indiP_sigmaMaxThreshDown, target, ipRecv, true ) < 0 )
1045  {
1046  log<software_error>( { __FILE__, __LINE__ } );
1047  return -1;
1048  }
1049 
1050  m_sigmaMaxThreshDown = target;
1051 
1052  log<text_log>( "set sigmaMaxThreshDown = " + std::to_string( m_sigmaMaxThreshDown ), logPrio::LOG_NOTICE );
1053  return 0;
1054 }
1055 
1056 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaPixThresh )( const pcf::IndiProperty &ipRecv )
1057 {
1058  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaPixThresh, ipRecv );
1059 
1060  float target;
1061 
1062  if( indiTargetUpdate( m_indiP_sigmaPixThresh, target, ipRecv, true ) < 0 )
1063  {
1064  log<software_error>( { __FILE__, __LINE__ } );
1065  return -1;
1066  }
1067 
1068  m_sigmaPixThresh = target;
1069 
1070  log<text_log>( "set sigmaMaxThreshDown = " + std::to_string( m_sigmaPixThresh ), logPrio::LOG_NOTICE );
1071  return 0;
1072 }
1073 
1074 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dx )( const pcf::IndiProperty &ipRecv )
1075 {
1076  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dx, ipRecv );
1077 
1078  float target;
1079 
1080  if( indiTargetUpdate( m_indiP_dx, target, ipRecv, true ) < 0 )
1081  {
1082  log<software_error>( { __FILE__, __LINE__ } );
1083  return -1;
1084  }
1085 
1086  m_dx = target;
1087 
1088  log<text_log>( "set dx = " + std::to_string( m_dx ), logPrio::LOG_NOTICE );
1089  return 0;
1090 }
1091 
1092 INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dy )( const pcf::IndiProperty &ipRecv )
1093 {
1094  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dy, ipRecv );
1095 
1096  float target;
1097 
1098  if( indiTargetUpdate( m_indiP_dy, target, ipRecv, true ) < 0 )
1099  {
1100  log<software_error>( { __FILE__, __LINE__ } );
1101  return -1;
1102  }
1103 
1104  m_dy = target;
1105 
1106  log<text_log>( "set dy = " + std::to_string( m_dy ), logPrio::LOG_NOTICE );
1107  return 0;
1108 }
1109 
1110 INDI_SETCALLBACK_DEFN( psfFit, m_indiP_fpsSource )( const pcf::IndiProperty &ipRecv )
1111 {
1112  INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fpsSource, ipRecv );
1113 
1114  if( ipRecv.find( "current" ) != true ) // this isn't valid
1115  {
1116  return 0;
1117  }
1118 
1119  std::lock_guard<std::mutex> guard( m_indiMutex );
1120 
1121  realT fps = ipRecv["current"].get<float>();
1122 
1123  if( fps != m_fps )
1124  {
1125 
1126  m_fps = fps;
1127 
1128  std::cerr << "got fps: " << m_fps << "\n";
1129 
1130  shmimMonitorT::m_restart = true;
1131  }
1132 
1133  return 0;
1134 }
1135 
1137 {
1139 }
1140 
1142 {
1143  return recordFGTimings( true );
1144 }
1145 
1146 } // namespace app
1147 } // namespace MagAOX
1148 
1149 #endif // psfFit_hpp
#define IMAGESTRUCT_FLOAT
Definition: ImageStruct.hpp:22
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
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2297
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1804
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
uint8_t m_dataType
The ImageStreamIO type code.
uint32_t m_height
The height of the image, once deinterlaced etc.
uint32_t m_width
The width of the images in the stream.
uint32_t m_height
The height of the images in the stream.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
The MagAO-X PSF Fitter.
Definition: psfFit.hpp:67
virtual int appLogic()
Implementation of the FSM for psfFit.
Definition: psfFit.hpp:482
pcf::IndiProperty m_indiP_values
Definition: psfFit.hpp:283
float m_dx
The offset in x to apply to non-skipped measurements.
Definition: psfFit.hpp:149
psfFit()
Default c'tor.
Definition: psfFit.hpp:325
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
Definition: psfFit.hpp:940
int reconfig()
Implementation of the framegrabber reconfig interface.
Definition: psfFit.hpp:958
float m_mnx
The mean x coord over the stats time.
Definition: psfFit.hpp:165
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition: psfFit.hpp:396
float realT
Floating point type in which to do all calculations.
Definition: psfFit.hpp:95
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaMaxThreshUp)
mx::sigproc::circularBufferIndex< float, cbIndexT > m_pcb
Circular buffer for max pixel (p=peak)
Definition: psfFit.hpp:154
bool m_skipped
Indicates that the image failed quality control and this is a skip frame.
Definition: psfFit.hpp:141
float m_sigmaMaxThreshDown
Definition: psfFit.hpp:124
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber these images can not be flipped
Definition: psfFit.hpp:101
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_dy)
uint16_t m_fitCircBuffMaxLength
Maximum length of the latency measurement circular buffers.
Definition: psfFit.hpp:114
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_dx)
float fps()
Implementation of the framegrabber fps interface.
Definition: psfFit.hpp:243
pcf::IndiProperty m_indiP_dx
Definition: psfFit.hpp:303
float m_mny
The mean y coord over the stats time.
Definition: psfFit.hpp:167
float m_x
The current x coordinate.
Definition: psfFit.hpp:143
float m_rmsp
The rms max pixel over the stats time.
Definition: psfFit.hpp:163
std::vector< float > m_ycbD
Vector for doing calcs on y COL coords.
Definition: psfFit.hpp:160
float m_rmsy
The rms y coord over the stats time.
Definition: psfFit.hpp:168
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaMaxThreshDown)
sem_t m_smSemaphore
Semaphore used to synchronize the fg thread and the sm thread.
Definition: psfFit.hpp:224
dev::telemeter< psfFit > telemeterT
Definition: psfFit.hpp:92
mx::sigproc::circularBufferIndex< float, cbIndexT > m_xcb
Circular buffer for x COL coords.
Definition: psfFit.hpp:155
pcf::IndiProperty m_indiP_reset
Definition: psfFit.hpp:285
dev::shmimMonitor< psfFit, darkShmimT > darkShmimMonitorT
The dark shmimMonitor type.
Definition: psfFit.hpp:83
virtual void loadConfig()
Definition: psfFit.hpp:414
pcf::IndiProperty m_indiP_dy
Definition: psfFit.hpp:306
~psfFit() noexcept
D'tor, declared and defined for noexcept.
Definition: psfFit.hpp:333
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
Definition: psfFit.hpp:910
std::vector< float > m_pcbD
Vector for doing calcs on max pixel.
Definition: psfFit.hpp:158
dev::frameGrabber< psfFit > frameGrabberT
Definition: psfFit.hpp:89
int recordTelem(const telem_fgtimings *)
Definition: psfFit.hpp:1141
pcf::IndiProperty m_indiP_sigmaPixThresh
Definition: psfFit.hpp:300
std::mutex m_imageMutex
Definition: psfFit.hpp:222
float m_fps
The frame rate from the source camera.
Definition: psfFit.hpp:152
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_deltaPixThresh)
float m_sigmaMaxThreshUp
Definition: psfFit.hpp:121
float m_last_y
The previous y coordinate.
Definition: psfFit.hpp:147
int allocate(const dev::shmimT &)
Definition: psfFit.hpp:570
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_statsTime)
float m_fitCircBuffMaxTime
Maximum time of the latency meaurement circular buffers.
Definition: psfFit.hpp:116
pcf::IndiProperty m_indiP_deltaPixThresh
Definition: psfFit.hpp:291
mx::improc::eigenImage< float > m_dark
Holds the dark image.
Definition: psfFit.hpp:135
float m_rmsx
The rms x coord over the stats time.
Definition: psfFit.hpp:166
pcf::IndiProperty m_indiP_fpsSource
Definition: psfFit.hpp:309
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_reset)
virtual void setupConfig()
Definition: psfFit.hpp:337
virtual int appShutdown()
Shutdown the app.
Definition: psfFit.hpp:559
dev::shmimMonitor< psfFit, refShmimT > refShmimMonitorT
The reference shmimMonitor type.
Definition: psfFit.hpp:86
mx::improc::eigenImage< float > m_ref
Holds the reference image.
Definition: psfFit.hpp:137
std::vector< float > m_xcbD
Vector for doing calcs on x COL coords.
Definition: psfFit.hpp:159
pcf::IndiProperty m_indiP_statsTime
Definition: psfFit.hpp:288
mx::sigproc::circularBufferIndex< float, cbIndexT > m_ycb
Circular buffer for y COL coords.
Definition: psfFit.hpp:156
float m_last_x
The previous x coordinate.
Definition: psfFit.hpp:144
float m_y
The current y coordinate.
Definition: psfFit.hpp:146
float m_mnp
The mean max pixel over the stats time.
Definition: psfFit.hpp:162
INDI_SETCALLBACK_DECL(psfFit, m_indiP_fpsSource)
virtual int appStartup()
Startup function.
Definition: psfFit.hpp:419
bool m_updated
Indicates that the coordinates were updated was updated.
Definition: psfFit.hpp:139
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
Definition: psfFit.hpp:895
pcf::IndiProperty m_indiP_sigmaMaxThreshUp
Definition: psfFit.hpp:294
float m_deltaPixThresh
Definition: psfFit.hpp:118
float m_dy
The offset in y to apply to non-skipped measurements.
Definition: psfFit.hpp:150
std::string m_fpsSource
Definition: psfFit.hpp:111
int processImage(void *curr_src, const dev::shmimT &)
Definition: psfFit.hpp:621
pcf::IndiProperty m_indiP_sigmaMaxThreshDown
Definition: psfFit.hpp:297
float m_sigmaPixThresh
Definition: psfFit.hpp:127
mx::improc::eigenImage< float > m_image
Holds the raw image.
Definition: psfFit.hpp:133
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaPixThresh)
dev::shmimMonitor< psfFit > shmimMonitorT
The base shmimMonitor type.
Definition: psfFit.hpp:80
friend class psfFit_test
Definition: psfFit.hpp:69
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
Definition: psfFit.hpp:905
#define FRAMEGRABBER_SETUP_CONFIG(cfig)
Call frameGrabberT::setupConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_LOGIC
Call frameGrabberT::appLogic with error checking for frameGrabber.
#define FRAMEGRABBER_APP_SHUTDOWN
Call frameGrabberT::appShutdown with error checking for frameGrabber.
#define FRAMEGRABBER_UPDATE_INDI
Call frameGrabberT::updateINDI with error checking for frameGrabber.
#define FRAMEGRABBER_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
#define CREATE_REG_INDI_NEW_REQUESTSWITCH(prop, name)
Create and register a NEW INDI property as a standard request switch, using the standard callback nam...
Definition: indiMacros.hpp:445
#define CREATE_REG_INDI_NEW_NUMBERF(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as float, using the standard callback na...
Definition: indiMacros.hpp:309
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
Definition: indiMacros.hpp:282
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
Definition: indiMacros.hpp:385
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:55
std::ostream & cerr()
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & ipRecv
Definition: MagAOXApp.hpp:3434
INDI_SETCALLBACK_DEFN(adcTracker, m_indiP_teldata)(const pcf
Definition: adcTracker.hpp:461
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_INFO
Informational. The info log level is the lowest level recorded during normal operations.
Definition: logPriority.hpp:49
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
Definition: logPriority.hpp:46
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_APP_SHUTDOWN
Call shmimMonitorT::appShutdown with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_LOGIC
Call shmimMonitorT::appLogic with error checking for shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for shmimMonitor.
#define SHMIMMONITOR_LOAD_CONFIG(cfig)
Call shmimMonitorT::loadConfig with error checking for shmimMonitor.
#define SHMIMMONITORT_SETUP_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::setupConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_LOGIC(SHMIMMONITORT)
Call shmimMonitorT::appLogic with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_SHUTDOWN(SHMIMMONITORT)
Call shmimMonitorT::appShutodwn with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_UPDATE_INDI
Call shmimMonitorT::updateINDI with error checking for shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_SETUP_CONFIG(cfig)
Call shmimMonitorT::setupConfig with error checking for shmimMonitor.
static std::string configSection()
Definition: psfFit.hpp:33
static std::string indiPrefix()
Definition: psfFit.hpp:38
A device base class which saves telemetry.
Definition: telemeter.hpp:69
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Definition: telemeter.hpp:281
static std::string indiPrefix()
Definition: psfFit.hpp:51
static std::string configSection()
Definition: psfFit.hpp:46
Software ERR log entry.
Log entry recording framegrabber timings.
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
Definition: telemeter.hpp:339
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
Definition: telemeter.hpp:325
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
Definition: telemeter.hpp:332
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
Definition: telemeter.hpp:314
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.
Definition: telemeter.hpp:346