API
pupilFit.hpp
Go to the documentation of this file.
1 /** \file pupilFit.hpp
2  * \brief The MagAO-X Pyramid Pupil Fitter application header
3  *
4  * \ingroup pupilFit_files
5  */
6 
7 #ifndef pupilFit_hpp
8 #define pupilFit_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 #include "pupilFitter.hpp"
14 
15 /** \defgroup pupilFit
16  * \brief The MagAO-X pyramid pupil fitter.
17  *
18  * <a href="../handbook/operating/software/apps/pupilFit.html">Application Documentation</a>
19  *
20  * \ingroup apps
21  *
22  */
23 
24 /** \defgroup pupilFit_files
25  * \ingroup pupilFit
26  */
27 
28 namespace MagAOX
29 {
30 namespace app
31 {
32 
33 struct refShmimT
34 {
35  static std::string configSection()
36  {
37  return "refShmim";
38  };
39 
40  static std::string indiPrefix()
41  {
42  return "ref";
43  };
44 };
45 
46 #define USEDEFSET (0)
47 #define USEREFIM (1)
48 #define USEUSERSET (2)
49 
50 /// The MagAO-X Pyramid Pupil Fitter
51 /**
52  * \ingroup pupilFit
53  */
54 class pupilFit : public MagAOXApp<true>, public dev::shmimMonitor<pupilFit>, public dev::shmimMonitor<pupilFit,refShmimT>, public dev::frameGrabber<pupilFit>, public dev::telemeter<pupilFit>
55 {
56  //Give the test harness access.
57  friend class pupilFit_test;
58 
59  friend class dev::shmimMonitor<pupilFit>;
60  friend class dev::shmimMonitor<pupilFit,refShmimT>;
61  friend class dev::frameGrabber<pupilFit>;
62 
63  friend class dev::telemeter<pupilFit>;
64 
65 public:
66  //The base shmimMonitor type
68 
70 
71  //The base frameGrabber type
73 
74  //The base telemeter type
76 
77  ///Floating point type in which to do all calculations.
78  typedef float realT;
79 
80  /** \name app::dev Configurations
81  *@{
82  */
83 
84  static constexpr bool c_frameGrabber_flippable = false; ///< app:dev config to tell framegrabber these images can not be flipped
85 
86  ///@}
87 
88 protected:
89 
90  /** \name Configurable Parameters
91  *@{
92  */
93 
94  std::string m_threshShmimName {"camwfs_thresh"}; ///<The name of the image stream for the thresholded images. Default is camwfs_thresh.
95  std::string m_edgeShmimName {"camwfs_edge"}; ///<The name of the image stream for the edge images. Default is camwfs_edge.
96 
97  float m_threshold {0.5};
98 
99  int m_numPupils {4}; ///< The number of pupils. Default is 4. 3 is also supported.
100  ///@}
101 
102  mx::improc::eigenImage<float> m_refIm;
103  mx::improc::eigenImage<float> m_fitIm;
104  mx::improc::eigenImage<float> m_edgeIm;
105 
107 
110 
111  IMAGE m_edgeShmim;
112  bool m_edgeShmimConnected {false};
113 
114  double m_defSetx1 {29.5};
115  double m_defSety1 {29.5};
116  double m_defSetD1 {56.0};
117 
118  double m_defSetx2 {89.5};
119  double m_defSety2 {29.5};
120  double m_defSetD2 {56.0};
121 
122  double m_defSetx3 {29.5};
123  double m_defSety3 {89.5};
124  double m_defSetD3 {56.0};
125 
126  double m_defSetx4 {89.5};
127  double m_defSety4 {89.5};
128  double m_defSetD4 {56.0};
129 
130  double m_userSetx1 {29.5};
131  double m_userSety1 {29.5};
132  double m_userSetD1 {56.0};
133 
134  double m_userSetx2 {89.5};
135  double m_userSety2 {29.5};
136  double m_userSetD2 {56.0};
137 
138  double m_userSetx3 {29.5};
139  double m_userSety3 {89.5};
140  double m_userSetD3 {56.0};
141 
142  double m_userSetx4 {89.5};
143  double m_userSety4 {89.5};
144  double m_userSetD4 {56.0};
145 
147 
148  bool m_refUpdated {false}; ///< Flag set if the online reference update is used.
149 
150  double m_setx1 {29.5};
151  double m_sety1 {29.5};
152  double m_setD1 {56.0};
153 
154  double m_setx2 {89.5};
155  double m_sety2 {29.5};
156  double m_setD2 {56.0};
157 
158  double m_setx3 {29.5};
159  double m_sety3 {89.5};
160  double m_setD3 {56.0};
161 
162  double m_setx4 {89.5};
163  double m_sety4 {89.5};
164  double m_setD4 {56.0};
165 
166  double m_avg_dx;
167  double m_avg_dy;
168 
169  bool m_averaging {false};
170  size_t m_navg {0};
171 
172  double m_avgx1_accum {0};
173  double m_avgx1sq_accum {0};
174 
175  double m_avgy1_accum {0};
176  double m_avgy1sq_accum {0};
177 
178  double m_avgD1_accum {0};
179  double m_avgD1sq_accum {0};
180 
181  double m_avgmed1_accum {0};
182  double m_avgmed1sq_accum {0};
183 
184  double m_avgx1 {0};
185  double m_varx1 {0};
186 
187  double m_avgy1 {0};
188  double m_vary1 {0};
189 
190  double m_avgD1 {0};
191  double m_varD1 {0};
192 
193  double m_avgmed1 {0};
194  double m_varmed1 {0};
195 
196  double m_avgx2_accum {0};
197  double m_avgx2sq_accum {0};
198 
199  double m_avgy2_accum {0};
200  double m_avgy2sq_accum {0};
201 
202  double m_avgD2_accum {0};
203  double m_avgD2sq_accum {0};
204 
205  double m_avgmed2_accum {0};
206  double m_avgmed2sq_accum {0};
207 
208  double m_avgx2 {0};
209  double m_varx2 {0};
210 
211  double m_avgy2 {0};
212  double m_vary2 {0};
213 
214  double m_avgD2 {0};
215  double m_varD2 {0};
216 
217  double m_avgmed2 {0};
218  double m_varmed2 {0};
219 
220  double m_avgx3_accum {0};
221  double m_avgx3sq_accum {0};
222 
223  double m_avgy3_accum {0};
224  double m_avgy3sq_accum {0};
225 
226  double m_avgD3_accum {0};
227  double m_avgD3sq_accum {0};
228 
229  double m_avgmed3_accum {0};
230  double m_avgmed3sq_accum {0};
231 
232  double m_avgx3 {0};
233  double m_varx3 {0};
234 
235  double m_avgy3 {0};
236  double m_vary3 {0};
237 
238  double m_avgD3 {0};
239  double m_varD3 {0};
240 
241  double m_avgmed3 {0};
242  double m_varmed3 {0};
243 
244  double m_avgx4_accum {0};
245  double m_avgx4sq_accum {0};
246 
247  double m_avgy4_accum {0};
248  double m_avgy4sq_accum {0};
249 
250  double m_avgD4_accum {0};
251  double m_avgD4sq_accum {0};
252 
253  double m_avgmed4_accum {0};
254  double m_avgmed4sq_accum {0};
255 
256  double m_avgx4 {0};
257  double m_varx4 {0};
258 
259  double m_avgy4 {0};
260  double m_vary4 {0};
261 
262  double m_avgD4 {0};
263  double m_varD4 {0};
264 
265  double m_avgmed4 {0};
266  double m_varmed4 {0};
267 
268  double m_avgxAll_accum {0};
269  double m_avgxAllsq_accum {0};
270 
271  double m_avgyAll_accum {0};
272  double m_avgyAllsq_accum {0};
273 
274  double m_avgDAll_accum {0};
275  double m_avgDAllsq_accum {0};
276 
277  double m_avgmedAll_accum {0};
279 
280  double m_avgxAll {0};
281  double m_varxAll {0};
282 
283  double m_avgyAll {0};
284  double m_varyAll {0};
285 
286  double m_avgDAll {0};
287  double m_varDAll {0};
288 
289  double m_avgmedAll {0};
290  double m_varmedAll {0};
291 
292 public:
293  /// Default c'tor.
294  pupilFit();
295 
296  /// D'tor, declared and defined for noexcept.
297  ~pupilFit() noexcept;
298 
299  virtual void setupConfig();
300 
301  /// Implementation of loadConfig logic, separated for testing.
302  /** This is called by loadConfig().
303  */
304  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
305 
306  virtual void loadConfig();
307 
308  /// Startup function
309  /**
310  *
311  */
312  virtual int appStartup();
313 
314  /// Implementation of the FSM for pupilFit.
315  /**
316  * \returns 0 on no critical error
317  * \returns -1 on an error requiring shutdown
318  */
319  virtual int appLogic();
320 
321  /// Shutdown the app.
322  /**
323  *
324  */
325  virtual int appShutdown();
326 
327  // shmimMonitor interface:
328  int allocate( const dev::shmimT &);
329 
330  int processImage( void* curr_src,
331  const dev::shmimT &
332  );
333 
334  // shmimMonitor interface for referenc:
335  int allocate( const refShmimT &);
336 
337  int processImage( void* curr_src,
338  const refShmimT &
339  );
340 
341 protected:
342 
343  bool m_updated {false}; //tells the f.g. that there is an actual image, not just a sem timeout
344 
345  sem_t m_smSemaphore {0}; ///< Semaphore used to synchronize the fg thread and the sm thread.
346 
347 public:
348 
349  /** \name dev::frameGrabber interface
350  *
351  * @{
352  */
353 
354  /// Implementation of the framegrabber configureAcquisition interface
355  /**
356  * \returns 0 on success
357  * \returns -1 on error
358  */
359  int configureAcquisition();
360 
361  /// Implementation of the framegrabber fps interface
362  /**
363  * \todo this needs to infer the stream fps and return it
364  */
365  float fps()
366  {
367  return 1.0;
368  }
369 
370  /// Implementation of the framegrabber startAcquisition interface
371  /**
372  * \returns 0 on success
373  * \returns -1 on error
374  */
375  int startAcquisition();
376 
377  /// Implementation of the framegrabber acquireAndCheckValid interface
378  /**
379  * \returns 0 on success
380  * \returns -1 on error
381  */
382  int acquireAndCheckValid();
383 
384  /// Implementation of the framegrabber loadImageIntoStream interface
385  /**
386  * \returns 0 on success
387  * \returns -1 on error
388  */
389  int loadImageIntoStream( void * dest /**< [in] */);
390 
391  /// Implementation of the framegrabber reconfig interface
392  /**
393  * \returns 0 on success
394  * \returns -1 on error
395  */
396  int reconfig();
397 
398  ///@}
399 
400 protected:
401 
402  /** \name INDI
403  * @{
404  */
405 
406  pcf::IndiProperty m_indiP_thresh;
407 
409 
410  pcf::IndiProperty m_indiP_averaging;
412 
413  pcf::IndiProperty m_indiP_numPupils;
414 
415  pcf::IndiProperty m_indiP_quad1;
416  pcf::IndiProperty m_indiP_quad2;
417  pcf::IndiProperty m_indiP_quad3;
418  pcf::IndiProperty m_indiP_quad4;
419 
420  pcf::IndiProperty m_indiP_avg;
421 
422  pcf::IndiProperty m_indiP_reload;
424 
425  pcf::IndiProperty m_indiP_update;
427 
428  pcf::IndiProperty m_indiP_refmode;
430 
431  ///@}
432 
433  /** \name Telemeter Interface
434  *
435  * @{
436  */
437  int checkRecordTimes();
438 
439  int recordTelem( const telem_fgtimings * );
440 
441  ///@}
442 };
443 
444 inline
445 pupilFit::pupilFit() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
446 {
448  return;
449 }
450 
451 inline
453 {
455  {
456  ImageStreamIO_destroyIm( &m_threshShmim );
457  }
458 
460  {
461  ImageStreamIO_destroyIm( &m_edgeShmim );
462  }
463 }
464 
465 inline
467 {
471  telemeterT::setupConfig(config);
472 
473  config.add("shmimMonitor.shmimName", "", "shmimMonitor.shmimName", argType::Required, "shmimMonitor", "shmimName", false, "string", "The name of the ImageStreamIO shared memory image. Will be used as /tmp/<shmimName>.im.shm. Default is camwfs_avg");
474 
475  config.add("fit.threshold", "", "fit.threshold", argType::Required, "fit", "threshold", false, "float", "The pupil finding threshold. 0 < threshold < 1");
476  config.add("fit.threshShmimName", "", "fit.threshShmimName", argType::Required, "fit", "threshShmimName", false, "float", "The name of the image stream for the thresholded images. Default is camwfs_thresh.");
477  config.add("fit.edgeShmimName", "", "fit.edgeShmimName", argType::Required, "fit", "edgeShmimName", false, "float", "The name of the image stream for the edge images. Default is camwfs_edge.");
478 
479  config.add("fit.numPupils", "", "fit.numPupils", argType::Required, "fit", "numPupils", false, "int", "The number of pupils. Default is 4. 3 is also supported.");
480  config.add("fit.pupMedIndex", "", "fit.pupMedIndex", argType::Required, "fit", "pupMedIndex", false, "float", "The index of the pupil median in a sorted quadrant.");
481 
482  config.add("cal.setx1", "", "cal.setx1", argType::Required, "cal", "setx1", false, "float", "The x set point for quad 1 (LL).");
483  config.add("cal.sety1", "", "cal.sety1", argType::Required, "cal", "sety1", false, "float", "The y set point for quad 1 (LL).");
484  config.add("cal.setD1", "", "cal.setD1", argType::Required, "cal", "setD1", false, "float", "The D set point for quad 1 (LL).");
485 
486  config.add("cal.setx2", "", "cal.setx2", argType::Required, "cal", "setx2", false, "float", "The x set point for quad 2 (LL).");
487  config.add("cal.sety2", "", "cal.sety2", argType::Required, "cal", "sety2", false, "float", "The y set point for quad 2 (LL).");
488  config.add("cal.setD2", "", "cal.setD2", argType::Required, "cal", "setD2", false, "float", "The D set point for quad 2 (LL).");
489 
490  config.add("cal.setx3", "", "cal.setx3", argType::Required, "cal", "setx3", false, "float", "The x set point for quad 3 (LL).");
491  config.add("cal.sety3", "", "cal.sety3", argType::Required, "cal", "sety3", false, "float", "The y set point for quad 3 (LL).");
492  config.add("cal.setD3", "", "cal.setD3", argType::Required, "cal", "setD3", false, "float", "The D set point for quad 3 (LL).");
493 
494  config.add("cal.setx4", "", "cal.setx4", argType::Required, "cal", "setx4", false, "float", "The x set point for quad 4 (LL).");
495  config.add("cal.sety4", "", "cal.sety4", argType::Required, "cal", "sety4", false, "float", "The y set point for quad 4 (LL).");
496  config.add("cal.setD4", "", "cal.setD4", argType::Required, "cal", "setD4", false, "float", "The D set point for quad 4 (LL).");
497 }
498 
499 
500 inline
501 int pupilFit::loadConfigImpl( mx::app::appConfigurator & _config )
502 {
503  shmimMonitorT::m_shmimName = "camwfs_avg";
504  shmimMonitorT::loadConfig(_config);
507 
508  frameGrabberT::loadConfig(_config);
509  telemeterT::loadConfig(_config);
510 
511  _config(m_threshold, "fit.threshold");
512  _config(m_threshShmimName, "fit.threshShmimName");
513  _config(m_edgeShmimName, "fit.edgeShmimName");
514  _config(m_numPupils, "fit.numPupils");
515  _config(m_fitter.m_pupMedIndex, "fit.pupMedIndex");
516 
517  _config(m_defSetx1, "cal.setx1");
518  _config(m_defSety1, "cal.sety1");
519  _config(m_defSetD1, "cal.setD1");
520 
521  _config(m_defSetx2, "cal.setx2");
522  _config(m_defSety2, "cal.sety2");
523  _config(m_defSetD2, "cal.setD2");
524 
525  _config(m_defSetx3, "cal.setx3");
526  _config(m_defSety3, "cal.sety3");
527  _config(m_defSetD3, "cal.setD3");
528 
529  _config(m_defSetx4, "cal.setx4");
530  _config(m_defSety4, "cal.sety4");
531  _config(m_defSetD4, "cal.setD4");
532 
533 
534  return 0;
535 }
536 
537 inline
539 {
540  loadConfigImpl(config);
541 }
542 
543 inline
545 {
546  if(shmimMonitorT::appStartup() < 0)
547  {
548  return log<software_error,-1>({__FILE__, __LINE__});
549  }
550 
552  {
553  return log<software_error,-1>({__FILE__, __LINE__});
554  }
555 
556  if(sem_init(&m_smSemaphore, 0,0) < 0)
557  {
558  log<software_critical>({__FILE__, __LINE__, errno,0, "Initializing S.M. semaphore"});
559  return -1;
560  }
561 
562  if(frameGrabberT::appStartup() < 0)
563  {
564  return log<software_error,-1>({__FILE__, __LINE__});
565  }
566 
567  if(telemeterT::appStartup() < 0)
568  {
569  return log<software_error,-1>({__FILE__, __LINE__});
570  }
571 
572  createStandardIndiNumber<float>( m_indiP_thresh, "threshold", 0, 1 ,0, "%0.2f", "Threshold");
573  m_indiP_thresh["current"].set(m_threshold);
574  m_indiP_thresh["target"].set(m_threshold);
576 
577  createStandardIndiToggleSw( m_indiP_averaging, "averaging", "Start/Stop Averaging");
578  m_indiP_averaging["toggle"].set(pcf::IndiElement::Off);
580  {
581  log<software_error>({__FILE__,__LINE__});
582  return -1;
583  }
584 
585  createROIndiNumber( m_indiP_numPupils, "numPupils", "Number of Pupils");
586  indi::addNumberElement<int>( m_indiP_numPupils, "value", 3, 4, 1, "%d", "");
587  m_indiP_numPupils["value"].set(m_numPupils);
589 
590  createROIndiNumber( m_indiP_quad1, "quadrant1", "Quadrant 1");
591  indi::addNumberElement<float>( m_indiP_quad1, "x", 0, 59, 0, "%0.2f", "center x");
592  indi::addNumberElement<float>( m_indiP_quad1, "dx", 0, 59, 0, "%0.2f", "delta-x");
593  indi::addNumberElement<float>( m_indiP_quad1, "y", 0, 59, 0, "%0.2f", "center x");
594  indi::addNumberElement<float>( m_indiP_quad1, "dy", 0, 59, 0, "%0.2f", "delta-y");
595  indi::addNumberElement<float>( m_indiP_quad1, "D", 0, 59, 0, "%0.2f", "diameter");
596  indi::addNumberElement<float>( m_indiP_quad1, "dD", 0, 59, 0, "%0.2f", "delta-D");
597  indi::addNumberElement<float>( m_indiP_quad1, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
598  indi::addNumberElement<float>( m_indiP_quad1, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
599  m_indiP_quad1["set-x"] = m_setx1;
600  indi::addNumberElement<float>( m_indiP_quad1, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
601  m_indiP_quad1["set-y"] = m_sety1;
602  indi::addNumberElement<float>( m_indiP_quad1, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
603  m_indiP_quad1["set-D"] = m_setD1;
604 
606 
607  createROIndiNumber( m_indiP_quad2, "quadrant2", "Quadrant 2");
608  indi::addNumberElement<float>( m_indiP_quad2, "x", 0, 59, 0, "%0.2f", "center x");
609  indi::addNumberElement<float>( m_indiP_quad2, "dx", 0, 59, 0, "%0.2f", "delta-x");
610  indi::addNumberElement<float>( m_indiP_quad2, "y", 0, 59, 0, "%0.2f", "center y");
611  indi::addNumberElement<float>( m_indiP_quad2, "dy", 0, 59, 0, "%0.2f", "delta-y");
612  indi::addNumberElement<float>( m_indiP_quad2, "D", 0, 59, 0, "%0.2f", "diameter");
613  indi::addNumberElement<float>( m_indiP_quad2, "dD", 0, 59, 0, "%0.2f", "delta-D");
614  indi::addNumberElement<float>( m_indiP_quad2, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
615  indi::addNumberElement<float>( m_indiP_quad2, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
616  m_indiP_quad2["set-x"] = m_setx2;
617  indi::addNumberElement<float>( m_indiP_quad2, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
618  m_indiP_quad2["set-y"] = m_sety2;
619  indi::addNumberElement<float>( m_indiP_quad2, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
620  m_indiP_quad2["set-D"] = m_setD2;
622 
623  createROIndiNumber( m_indiP_quad3, "quadrant3", "Quadrant 3");
624  indi::addNumberElement<float>( m_indiP_quad3, "x", 0, 59, 0, "%0.2f", "center x");
625  indi::addNumberElement<float>( m_indiP_quad3, "dx", 0, 59, 0, "%0.2f", "delta-x");
626  indi::addNumberElement<float>( m_indiP_quad3, "y", 0, 59, 0, "%0.2f", "center y");
627  indi::addNumberElement<float>( m_indiP_quad3, "dy", 0, 59, 0, "%0.2f", "delta-y");
628  indi::addNumberElement<float>( m_indiP_quad3, "D", 0, 59, 0, "%0.2f", "diameter");
629  indi::addNumberElement<float>( m_indiP_quad3, "dD", 0, 59, 0, "%0.2f", "delta-D");
630  indi::addNumberElement<float>( m_indiP_quad3, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
631  indi::addNumberElement<float>( m_indiP_quad3, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
632  m_indiP_quad3["set-x"] = m_setx3;
633  indi::addNumberElement<float>( m_indiP_quad3, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
634  m_indiP_quad3["set-y"] = m_sety3;
635  indi::addNumberElement<float>( m_indiP_quad3, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
636  m_indiP_quad3["set-D"] = m_setD3;
638 
639  if(m_numPupils != 3)
640  {
641  createROIndiNumber( m_indiP_quad4, "quadrant4", "Quadrant 4");
642  indi::addNumberElement<float>( m_indiP_quad4, "x", 0, 59, 0, "%0.2f", "center x");
643  indi::addNumberElement<float>( m_indiP_quad4, "dx", 0, 59, 0, "%0.2f", "delta-x");
644  indi::addNumberElement<float>( m_indiP_quad4, "y", 0, 59, 0, "%0.2f", "center y");
645  indi::addNumberElement<float>( m_indiP_quad4, "dy", 0, 59, 0, "%0.2f", "delta-y");
646  indi::addNumberElement<float>( m_indiP_quad4, "D", 0, 59, 0, "%0.2f", "diameter");
647  indi::addNumberElement<float>( m_indiP_quad4, "dD", 0, 59, 0, "%0.2f", "delta-D");
648  indi::addNumberElement<float>( m_indiP_quad4, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
649  indi::addNumberElement<float>( m_indiP_quad4, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
650  m_indiP_quad4["set-x"] = m_setx4;
651  indi::addNumberElement<float>( m_indiP_quad4, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
652  m_indiP_quad4["set-y"] = m_sety4;
653  indi::addNumberElement<float>( m_indiP_quad4, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
654  m_indiP_quad4["set-D"] = m_setD4;
656  }
657 
658  createROIndiNumber( m_indiP_avg, "average", "Average");
659  indi::addNumberElement<float>( m_indiP_avg, "x", 0, 59, 0, "%0.2f", "center x");
660  indi::addNumberElement<float>( m_indiP_avg, "dx", 0, 59, 0, "%0.2f", "delta-x");
661  indi::addNumberElement<float>( m_indiP_avg, "y", 0, 59, 0, "%0.2f", "center y");
662  indi::addNumberElement<float>( m_indiP_avg, "dy", 0, 59, 0, "%0.2f", "delta-y");
663  indi::addNumberElement<float>( m_indiP_avg, "D", 0, 59, 0, "%0.2f", "diameter");
664  indi::addNumberElement<float>( m_indiP_avg, "dD", 0, 59, 0, "%0.2f", "delta-D");
666 
667  createStandardIndiRequestSw( m_indiP_reload, "setpt_reload", "Reload Calibration");
668  m_indiP_reload["request"].set(pcf::IndiElement::Off);
670  {
671  log<software_error>({__FILE__,__LINE__});
672  return -1;
673  }
674 
675  createStandardIndiRequestSw( m_indiP_update, "setpt_current", "Set Reference");
676  m_indiP_update["request"].set(pcf::IndiElement::Off);
678  {
679  log<software_error>({__FILE__,__LINE__});
680  return -1;
681  }
682 
683  createStandardIndiSelectionSw( m_indiP_refmode, "setpt_mode", {"default", "refim", "user"}, "Reference Mode");
685  {
686  m_indiP_refmode["default"].set(pcf::IndiElement::Off);
687  m_indiP_refmode["refim"].set(pcf::IndiElement::On);
688  m_indiP_refmode["user"].set(pcf::IndiElement::Off);
689  }
691  {
692  m_indiP_refmode["default"].set(pcf::IndiElement::Off);
693  m_indiP_refmode["refim"].set(pcf::IndiElement::Off);
694  m_indiP_refmode["user"].set(pcf::IndiElement::On);
695  }
696  else
697  {
698  m_indiP_refmode["default"].set(pcf::IndiElement::On);
699  m_indiP_refmode["refim"].set(pcf::IndiElement::Off);
700  m_indiP_refmode["user"].set(pcf::IndiElement::Off);
701  }
702 
704  {
705  log<software_error>({__FILE__,__LINE__});
706  return -1;
707  }
708 
710 
711  return 0;
712 }
713 
714 inline
716 {
717  if( shmimMonitorT::appLogic() < 0)
718  {
719  return log<software_error,-1>({__FILE__,__LINE__});
720  }
721 
722  if( refShmimMonitorT::appLogic() < 0)
723  {
724  return log<software_error,-1>({__FILE__,__LINE__});
725  }
726 
727  if( frameGrabberT::appLogic() < 0)
728  {
729  return log<software_error,-1>({__FILE__,__LINE__});
730  }
731 
732  if( telemeterT::appLogic() < 0)
733  {
734  return log<software_error,-1>({__FILE__,__LINE__});
735  }
736 
737  std::lock_guard<std::mutex> guard(m_indiMutex);
740 
742  {
743  updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::Off);
744  updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::On);
745  updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::Off);
746  }
747  else if(m_setPointSource == USEUSERSET)
748  {
749  updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::Off);
750  updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::Off);
751  updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::On);
752  }
753  else
754  {
755  updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::On);
756  updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::Off);
757  updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::Off);
758  }
759 
762 
763  if(frameGrabberT::updateINDI() < 0)
764  {
765  log<software_error>({__FILE__, __LINE__});
766  }
767 
768  return 0;
769 }
770 
771 inline
773 {
778 
779  return 0;
780 }
781 
782 inline
783 int pupilFit::allocate(const dev::shmimT & dummy)
784 {
785  static_cast<void>(dummy);
786 
787  std::lock_guard<std::mutex> guard(m_indiMutex);
788 
791 
792  m_fitter.m_numPupils = m_numPupils;
794  m_fitter.m_thresh = m_threshold;
795 
797  {
798  mx::improc::eigenImage<float> refim, refedge;
799  refim = m_refIm; //cuz it's modified by fitter.
800  if(m_fitter.fit(refim, refedge) < 0)
801  {
802  return log<software_error, -1>({__FILE__, __LINE__, "error from fitter for reference"});
803  }
804 
805  m_setx1 = m_fitter.m_avgx[0];
806  m_sety1 = m_fitter.m_avgy[0];
807  m_setD1 = 2*m_fitter.m_avgr[0];
808 
809  m_setx2 = m_fitter.m_avgx[1];
810  m_sety2 = m_fitter.m_avgy[1];
811  m_setD2 = 2*m_fitter.m_avgr[1];
812 
813  m_setx3 = m_fitter.m_avgx[2];
814  m_sety3 = m_fitter.m_avgy[2];
815  m_setD3 = 2*m_fitter.m_avgr[2];
816 
817  m_setx4 = m_fitter.m_avgx[3];
818  m_sety4 = m_fitter.m_avgy[3];
819  m_setD4 = 2*m_fitter.m_avgr[3];
820 
821  log<text_log>("Fit to reference image: ");
822  log<text_log>("Quad 1 set points: " + std::to_string(m_setx1) + " " + std::to_string(m_sety1) + " " + std::to_string(m_setD1));
823  log<text_log>("Quad 2 set points: " + std::to_string(m_setx2) + " " + std::to_string(m_sety2) + " " + std::to_string(m_setD2));
824  log<text_log>("Quad 3 set points: " + std::to_string(m_setx3) + " " + std::to_string(m_sety3) + " " + std::to_string(m_setD3));
825  log<text_log>("Quad 4 set points: " + std::to_string(m_setx4) + " " + std::to_string(m_sety4) + " " + std::to_string(m_setD4));
826  }
827  else
828  {
830  {
831  if(m_refIm.rows()!=0 || m_refIm.cols() != 0) //only complain if the ref image has been loaded
832  {
833  log<text_log>("Reference image size does not match", logPrio::LOG_ERROR);
834  }
835  }
836 
838  {
842 
846 
850 
851  if(m_numPupils == 4)
852  {
856  }
857  log<text_log>("Using user set-points");
858 
859  }
860  else
861  {
865 
869 
873 
874  if(m_numPupils == 4)
875  {
879  }
880  log<text_log>("Set default set-points");
881  }
882  }
883 
884  uint32_t imsize[3];
885  imsize[0] = shmimMonitorT::m_width;
886  imsize[1] = shmimMonitorT::m_height;
887  imsize[2] = 1;
888 
890  {
891  ImageStreamIO_destroyIm( &m_threshShmim );
892  m_threshShmimConnected = false;
893  }
894 
896  {
897  ImageStreamIO_destroyIm( &m_edgeShmim );
898  m_edgeShmimConnected = false;
899  }
900 
901  ImageStreamIO_createIm_gpu(&m_threshShmim , m_threshShmimName.c_str(), 3, imsize, shmimMonitorT::m_dataType, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL,0);
902  m_threshShmimConnected = true;
903 
904  ImageStreamIO_createIm_gpu(&m_edgeShmim , m_edgeShmimName.c_str(), 3, imsize, shmimMonitorT::m_dataType, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL,0);
905  m_edgeShmimConnected = true;
906 
908  {
909  }
910 
911  return 0;
912 }
913 
914 inline
915 int pupilFit::processImage( void* curr_src,
916  const dev::shmimT & dummy
917  )
918 {
919  static_cast<void>(dummy);
920 
921  for(unsigned nn=0; nn < shmimMonitorT::m_width*shmimMonitorT::m_height; ++nn)
922  {
923  m_fitIm.data()[nn] += ((float*)curr_src) [nn];
924  }
925 
926  m_fitter.m_thresh = m_threshold;
927 
928  m_fitter.fit(m_fitIm, m_edgeIm);
929 
930 
931  {//mutex scope
932 
933  std::lock_guard<std::mutex> guard(m_indiMutex);
934  m_indiP_quad1["set-x"].set(m_setx1);
935  m_indiP_quad1["x"].set(m_fitter.m_avgx[0]);
936  m_indiP_quad1["dx"].set(m_fitter.m_avgx[0]-m_setx1);
937  m_indiP_quad1["set-y"].set(m_sety1);
938  m_indiP_quad1["y"].set(m_fitter.m_avgy[0]);
939  m_indiP_quad1["dy"].set(m_fitter.m_avgy[0]-m_sety1);
940  m_indiP_quad1["set-D"].set(m_setD1);
941  m_indiP_quad1["D"].set(2*m_fitter.m_avgr[0]);
942  m_indiP_quad1["dD"].set(2*m_fitter.m_avgr[0]-m_setD1);
943  m_indiP_quad1["med"].set(m_fitter.m_med[0]);
944  m_indiP_quad1.setState (INDI_BUSY);
945  m_indiDriver->sendSetProperty (m_indiP_quad1);
946 
947  m_indiP_quad2["set-x"].set(m_setx2);
948  m_indiP_quad2["x"].set(m_fitter.m_avgx[1]);
949  m_indiP_quad2["dx"].set(m_fitter.m_avgx[1]-m_setx2);
950  m_indiP_quad2["set-y"].set(m_sety2);
951  m_indiP_quad2["y"].set(m_fitter.m_avgy[1]);
952  m_indiP_quad2["dy"].set(m_fitter.m_avgy[1]-m_sety2);
953  m_indiP_quad2["set-D"].set(m_setD2);
954  m_indiP_quad2["D"].set(2*m_fitter.m_avgr[1]);
955  m_indiP_quad2["dD"].set(2*m_fitter.m_avgr[1]-m_setD2);
956  m_indiP_quad2["med"].set(m_fitter.m_med[1]);
957  m_indiP_quad2.setState (INDI_BUSY);
958  m_indiDriver->sendSetProperty (m_indiP_quad2);
959 
960  m_indiP_quad3["set-x"].set(m_setx3);
961  m_indiP_quad3["x"].set(m_fitter.m_avgx[2]);
962  m_indiP_quad3["dx"].set(m_fitter.m_avgx[2]-m_setx3);
963  m_indiP_quad3["set-y"].set(m_sety3);
964  m_indiP_quad3["y"].set(m_fitter.m_avgy[2]);
965  m_indiP_quad3["dy"].set(m_fitter.m_avgy[2]-m_sety3);
966  m_indiP_quad3["set-D"].set(m_setD3);
967  m_indiP_quad3["D"].set(2*m_fitter.m_avgr[2]);
968  m_indiP_quad3["dD"].set(2*m_fitter.m_avgr[2]-m_setD3);
969  m_indiP_quad3["med"].set(m_fitter.m_med[2]);
970  m_indiP_quad3.setState (INDI_BUSY);
971  m_indiDriver->sendSetProperty (m_indiP_quad3);
972 
973  if(m_numPupils == 3)
974  {
975  m_indiP_avg["x"].set(.333*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2]));
976  m_indiP_avg["y"].set(.333*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2]));
977  m_indiP_avg["D"].set(.667*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2]));
978 
979  m_avg_dx = .333*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2] + m_fitter.m_avgx[3]) - 0.25*(m_setx1 + m_setx2 + m_setx3 + m_setx4);
980  m_avg_dy = .333*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2] + m_fitter.m_avgy[3]) - 0.25*(m_sety1 + m_sety2 + m_sety3 + m_sety4);
981 
982 
983  m_indiP_avg["dx"].set(.333*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2]) - 0.333*(m_setx1 + m_setx2 + m_setx3));
984  m_indiP_avg["dy"].set(.333*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2]) - 0.333*(m_sety1 + m_sety2 + m_sety3));
985  m_indiP_avg["dD"].set(.667*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2]) - 0.333*(m_setD1 + m_setD2 + m_setD3));
986  }
987  else
988  {
989  m_indiP_quad4["set-x"].set(m_setx4);
990  m_indiP_quad4["x"].set(m_fitter.m_avgx[3]);
991  m_indiP_quad4["dx"].set(m_fitter.m_avgx[3]-m_setx4);
992  m_indiP_quad4["set-y"].set(m_sety4);
993  m_indiP_quad4["y"].set(m_fitter.m_avgy[3]);
994  m_indiP_quad4["dy"].set(m_fitter.m_avgy[3]-m_sety4);
995  m_indiP_quad4["set-D"].set(m_setD4);
996  m_indiP_quad4["D"].set(2*m_fitter.m_avgr[3]);
997  m_indiP_quad4["dD"].set(2*m_fitter.m_avgr[3]-m_setD4);
998  m_indiP_quad4["med"].set(m_fitter.m_med[3]);
999  m_indiP_quad4.setState (INDI_BUSY);
1000  m_indiDriver->sendSetProperty (m_indiP_quad4);
1001 
1002  m_indiP_avg["x"].set(.25*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2] + m_fitter.m_avgx[3]));
1003  m_indiP_avg["y"].set(.25*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2] + m_fitter.m_avgy[3]));
1004  m_indiP_avg["D"].set(.5*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2] + m_fitter.m_avgr[3]));
1005 
1006  m_avg_dx = .25*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2] + m_fitter.m_avgx[3]) - 0.25*(m_setx1 + m_setx2 + m_setx3 + m_setx4);
1007  m_avg_dy = .25*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2] + m_fitter.m_avgy[3]) - 0.25*(m_sety1 + m_sety2 + m_sety3 + m_sety4);
1008 
1009  m_indiP_avg["dx"].set(.25*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2] + m_fitter.m_avgx[3]) - 0.25*(m_setx1 + m_setx2 + m_setx3 + m_setx4));
1010  m_indiP_avg["dy"].set(.25*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2] + m_fitter.m_avgy[3]) - 0.25*(m_sety1 + m_sety2 + m_sety3 + m_sety4));
1011  m_indiP_avg["dD"].set(.5*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2] + m_fitter.m_avgr[3]) - 0.25*(m_setD1 + m_setD2 + m_setD3 + m_setD4));
1012  m_indiDriver->sendSetProperty (m_indiP_avg);
1013 
1014  }
1015 
1016  }
1017 
1018  //signal framegrabber
1019 //Now tell the f.g. to get going
1020  m_updated = true;
1021  if(sem_post(&m_smSemaphore) < 0)
1022  {
1023  log<software_critical>({__FILE__, __LINE__, errno, 0, "Error posting to semaphore"});
1024  return -1;
1025  }
1026 
1027 
1028  if(m_averaging)
1029  {
1030  ++m_navg;
1031 
1032  m_avgx1_accum += m_fitter.m_avgx[0];
1033  m_avgx1sq_accum += m_fitter.m_avgx[0]*m_fitter.m_avgx[0];
1034 
1035  m_avgy1_accum += m_fitter.m_avgy[0];
1036  m_avgy1sq_accum += m_fitter.m_avgy[0]*m_fitter.m_avgy[0];
1037 
1038  m_avgD1_accum += 2*m_fitter.m_avgr[0];
1039  m_avgD1sq_accum += 4*m_fitter.m_avgr[0]*m_fitter.m_avgr[0];
1040 
1041  m_avgmed1_accum += m_fitter.m_med[0];
1042  m_avgmed1sq_accum += m_fitter.m_med[0]*m_fitter.m_med[0];
1043 
1046 
1049 
1052 
1055 
1056  m_avgx2_accum += m_fitter.m_avgx[1];
1057  m_avgx2sq_accum += m_fitter.m_avgx[1]*m_fitter.m_avgx[1];
1058 
1059  m_avgy2_accum += m_fitter.m_avgy[1];
1060  m_avgy2sq_accum += m_fitter.m_avgy[1]*m_fitter.m_avgy[1];
1061 
1062  m_avgD2_accum += 2*m_fitter.m_avgr[1];
1063  m_avgD2sq_accum += 4*m_fitter.m_avgr[1]*m_fitter.m_avgr[1];
1064 
1065  m_avgmed2_accum += m_fitter.m_med[1];
1066  m_avgmed2sq_accum += m_fitter.m_med[1]*m_fitter.m_med[1];
1067 
1070 
1073 
1076 
1079 
1080 
1081 
1082  m_avgx3_accum += m_fitter.m_avgx[2];
1083  m_avgx3sq_accum += m_fitter.m_avgx[2]*m_fitter.m_avgx[2];
1084 
1085  m_avgy3_accum += m_fitter.m_avgy[2];
1086  m_avgy3sq_accum += m_fitter.m_avgy[2]*m_fitter.m_avgy[2];
1087 
1088  m_avgD3_accum += 2*m_fitter.m_avgr[2];
1089  m_avgD3sq_accum += 4*m_fitter.m_avgr[2]*m_fitter.m_avgr[2];
1090 
1091  m_avgmed3_accum += m_fitter.m_med[2];
1092  m_avgmed3sq_accum += m_fitter.m_med[2]*m_fitter.m_med[2];
1093 
1096 
1099 
1102 
1105 
1106  if(m_numPupils == 3)
1107  {
1108  double tmp = 0.333*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1109  m_avgxAll_accum += tmp;
1110  m_avgxAllsq_accum += tmp*tmp;
1111 
1112  tmp = 0.333*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]);
1113  m_avgyAll_accum += tmp;
1114  m_avgyAllsq_accum += tmp*tmp;
1115 
1116  tmp = 2*0.333*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]);
1117  m_avgDAll_accum += tmp;
1118  m_avgDAllsq_accum += tmp*tmp;
1119 
1120  tmp = 0.333*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]);
1121  m_avgmedAll_accum += tmp;
1122  m_avgmedAllsq_accum += tmp*tmp;
1123 
1126 
1129 
1132 
1135 
1136 
1137  std::cerr << "****************************************************************\n";
1138  std::cerr << "Averaged: " << m_navg << "\n";
1139  std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1140  std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1141  std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1142  std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1143  std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1144  std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1145  std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1146  std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1147  std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1148  std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1149  std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1150  std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1151  std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1152  std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1153  std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1154  std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1155  }
1156  else
1157  {
1158  m_avgx4_accum += m_fitter.m_avgx[3];
1159  m_avgx4sq_accum += m_fitter.m_avgx[3]*m_fitter.m_avgx[3];
1160 
1161  m_avgy4_accum += m_fitter.m_avgy[3];
1162  m_avgy4sq_accum += m_fitter.m_avgy[3]*m_fitter.m_avgy[3];
1163 
1164  m_avgD4_accum += 2*m_fitter.m_avgr[3];
1165  m_avgD4sq_accum += 4*m_fitter.m_avgr[3]*m_fitter.m_avgr[3];
1166 
1167  m_avgmed4_accum += m_fitter.m_med[3];
1168  m_avgmed4sq_accum += m_fitter.m_med[3]*m_fitter.m_med[3];
1169 
1172 
1175 
1178 
1181 
1182 
1183  double tmp = 0.25*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1184  m_avgxAll_accum += tmp;
1185  m_avgxAllsq_accum += tmp*tmp;
1186 
1187  tmp = 0.25*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]+m_fitter.m_avgy[3]);
1188  m_avgyAll_accum += tmp;
1189  m_avgyAllsq_accum += tmp*tmp;
1190 
1191  tmp = 2*0.25*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]+m_fitter.m_avgr[3]);
1192  m_avgDAll_accum += tmp;
1193  m_avgDAllsq_accum += tmp*tmp;
1194 
1195  tmp = 0.25*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]+m_fitter.m_med[3]);
1196  m_avgmedAll_accum += tmp;
1197  m_avgmedAllsq_accum += tmp*tmp;
1198 
1201 
1204 
1207 
1210 
1211 
1212  std::cerr << "****************************************************************\n";
1213  std::cerr << "Averaged: " << m_navg << "\n";
1214  std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1215  std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1216  std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1217  std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1218  std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1219  std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1220  std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1221  std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1222  std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1223  std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1224  std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1225  std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1226  std::cerr << "Average x4: " << m_avgx4 << " +/- " << sqrt(m_varx4) << "\n";
1227  std::cerr << "Average y4: " << m_avgy4 << " +/- " << sqrt(m_vary4) << "\n";
1228  std::cerr << "Average D4: " << m_avgD4 << " +/- " << sqrt(m_varD4) << "\n";
1229  std::cerr << "Average med4: " << m_avgmed4 << " +/- " << sqrt(m_varmed4) << "\n\n";
1230  std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1231  std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1232  std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1233  std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1234  }
1235  }
1236 
1237  m_threshShmim.md->write=1;
1238  m_edgeShmim.md->write=1;
1239 
1240  clock_gettime(CLOCK_REALTIME, &m_threshShmim.md->writetime);
1241  m_edgeShmim.md->writetime = m_threshShmim.md->writetime;
1242 
1243  m_threshShmim.md->atime = m_threshShmim.md->writetime;
1244  m_edgeShmim.md->atime = m_threshShmim.md->writetime;
1245 
1246  m_threshShmim.md->cnt0++;
1247  m_edgeShmim.md->cnt0++;
1248 
1249  memcpy(m_threshShmim.array.raw, m_fitIm.data(), m_fitIm.rows()*m_fitIm.cols()*sizeof(float));
1250  memcpy(m_edgeShmim.array.raw, m_edgeIm.data(), m_edgeIm.rows()*m_edgeIm.cols()*sizeof(float));
1251 
1252  m_threshShmim.md->write=0;
1253  m_edgeShmim.md->write=0;
1254 
1255  ImageStreamIO_sempost(&m_threshShmim,-1);
1256  ImageStreamIO_sempost(&m_edgeShmim,-1);
1257 
1258  return 0;
1259 }
1260 
1261 inline
1262 int pupilFit::allocate(const refShmimT & dummy)
1263 {
1264  static_cast<void>(dummy);
1265 
1266  std::lock_guard<std::mutex> guard(m_indiMutex);
1267 
1269  {
1270  return log<software_error,-1>({__FILE__, __LINE__, "reference is not float"});
1271  }
1272 
1274 
1275  return 0;
1276 }
1277 
1278 inline
1279 int pupilFit::processImage( void* curr_src,
1280  const refShmimT & dummy
1281  )
1282 {
1283  static_cast<void>(dummy);
1284 
1285  for(unsigned nn=0; nn < refShmimMonitorT::m_width*refShmimMonitorT::m_height; ++nn)
1286  {
1287  m_refIm.data()[nn] += ((float*)curr_src) [nn];
1288  }
1289 
1290  log<text_log>("reference updated", logPrio::LOG_NOTICE);
1291 
1292  shmimMonitorT::m_restart = true;
1293 
1294  return 0;
1295 }
1296 
1297 inline
1299 {
1300  std::unique_lock<std::mutex> lock(m_indiMutex);
1301 
1304  frameGrabberT::m_dataType = _DATATYPE_FLOAT;
1305 
1306  return 0;
1307 }
1308 
1309 inline
1311 {
1312  return 0;
1313 }
1314 
1315 inline
1317 {
1318  timespec ts;
1319 
1320  if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
1321  {
1322  log<software_critical>({__FILE__,__LINE__,errno,0,"clock_gettime"});
1323  return -1;
1324  }
1325 
1326  ts.tv_sec += 1;
1327 
1328  if(sem_timedwait(&m_smSemaphore, &ts) == 0)
1329  {
1330  if( m_updated )
1331  {
1332  clock_gettime(CLOCK_REALTIME, &m_currImageTimestamp);
1333  return 0;
1334  }
1335  else
1336  {
1337  return 1;
1338  }
1339  }
1340  else
1341  {
1342  return 1;
1343  }
1344 }
1345 
1346 inline
1348 {
1349  ((float *) dest)[0] = m_avg_dx;
1350  ((float *) dest)[1] = m_avg_dy;
1351 
1352  m_updated = false;
1353  return 0;
1354 }
1355 
1356 inline
1358 {
1359  return 0;
1360 }
1361 
1362 INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_thresh)(const pcf::IndiProperty & ipRecv)
1363 {
1364  if(ipRecv.getName() != m_indiP_thresh.getName())
1365  {
1366  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1367  return -1;
1368  }
1369 
1370  float target;
1371 
1372  if( indiTargetUpdate( m_indiP_thresh, target, ipRecv, true) < 0)
1373  {
1374  log<software_error>({__FILE__,__LINE__});
1375  return -1;
1376  }
1377 
1378  m_threshold = target;
1379 
1380  if(m_setPointSource == USEREFIM) shmimMonitorT::m_restart = true; //need to re-process the reference
1381 
1382  log<text_log>("set threshold = " + std::to_string(m_threshold), logPrio::LOG_NOTICE);
1383  return 0;
1384 }
1385 
1386 INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_averaging)(const pcf::IndiProperty & ipRecv)
1387 {
1388  if(ipRecv.getName() != m_indiP_averaging.getName())
1389  {
1390  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1391  return -1;
1392  }
1393 
1394  if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1395  {
1396 
1397  m_avgx1_accum = 0;
1398  m_avgx1sq_accum = 0;
1399  m_avgy1_accum = 0;
1400  m_avgy1sq_accum = 0;
1401  m_avgD1_accum = 0;
1402  m_avgD1sq_accum = 0;
1403  m_avgmed1_accum = 0;
1404  m_avgmed1sq_accum = 0;
1405 
1406  m_avgx2_accum = 0;
1407  m_avgx2sq_accum = 0;
1408  m_avgy2_accum = 0;
1409  m_avgy2sq_accum = 0;
1410  m_avgD2_accum = 0;
1411  m_avgD2sq_accum = 0;
1412  m_avgmed2_accum = 0;
1413  m_avgmed2sq_accum = 0;
1414 
1415  m_avgx3_accum = 0;
1416  m_avgx3sq_accum = 0;
1417  m_avgy3_accum = 0;
1418  m_avgy3sq_accum = 0;
1419  m_avgD3_accum = 0;
1420  m_avgD3sq_accum = 0;
1421  m_avgmed3_accum = 0;
1422  m_avgmed3sq_accum = 0;
1423 
1424  m_avgx4_accum = 0;
1425  m_avgx4sq_accum = 0;
1426  m_avgy4_accum = 0;
1427  m_avgy4sq_accum = 0;
1428  m_avgD4_accum = 0;
1429  m_avgD4sq_accum = 0;
1430  m_avgmed4_accum = 0;
1431  m_avgmed4sq_accum = 0;
1432 
1433  m_avgxAll_accum = 0;
1434  m_avgxAllsq_accum = 0;
1435  m_avgyAll_accum = 0;
1436  m_avgyAllsq_accum = 0;
1437  m_avgDAll_accum = 0;
1438  m_avgDAllsq_accum = 0;
1439  m_avgmedAll_accum = 0;
1440  m_avgmedAllsq_accum = 0;
1441 
1442  m_navg = 0;
1443  m_averaging = true;
1444 
1445  updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::On, INDI_BUSY);
1446 
1447  log<text_log>("began averaging");
1448 
1449  }
1450  else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1451  {
1452  m_averaging = false;
1453  updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1454 
1455  log<text_log>("stopped averaging");
1456  }
1457 
1458  return 0;
1459 }
1460 
1461 INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_reload)(const pcf::IndiProperty & ipRecv)
1462 {
1463  if(ipRecv.getName() != m_indiP_reload.getName())
1464  {
1465  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1466  return -1;
1467  }
1468 
1469  if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1470  {
1471  log<text_log>("reloading");
1472  shmimMonitorT::m_restart = 1;
1473  }
1474 
1475  return 0;
1476 }
1477 
1478 INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_update)(const pcf::IndiProperty & ipRecv)
1479 {
1480  if(ipRecv.getName() != m_indiP_update.getName())
1481  {
1482  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1483  return -1;
1484  }
1485 
1486  if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1487  {
1488  std::lock_guard<std::mutex> guard(m_indiMutex);
1489 
1490  m_setx1 = m_indiP_quad1["x"].get<float>();
1491  m_sety1 = m_indiP_quad1["y"].get<float>();
1492  m_setD1 = m_indiP_quad1["D"].get<float>();
1493 
1494  m_setx2 = m_indiP_quad2["x"].get<float>();
1495  m_sety2 = m_indiP_quad2["y"].get<float>();
1496  m_setD2 = m_indiP_quad2["D"].get<float>();
1497 
1498  m_setx3 = m_indiP_quad3["x"].get<float>();
1499  m_sety3 = m_indiP_quad3["y"].get<float>();
1500  m_setD3 = m_indiP_quad3["D"].get<float>();
1501 
1502  log<text_log>("Recorded current set-points: ");
1503  log<text_log>("Quad 1 set points: " + std::to_string(m_setx1) + " " + std::to_string(m_sety1) + " " + std::to_string(m_setD1));
1504  log<text_log>("Quad 2 set points: " + std::to_string(m_setx2) + " " + std::to_string(m_sety2) + " " + std::to_string(m_setD2));
1505  log<text_log>("Quad 3 set points: " + std::to_string(m_setx3) + " " + std::to_string(m_sety3) + " " + std::to_string(m_setD3));
1506 
1507  if(m_numPupils == 4)
1508  {
1509  m_setx4 = m_indiP_quad4["x"].get<float>();
1510  m_sety4 = m_indiP_quad4["y"].get<float>();
1511  m_setD4 = m_indiP_quad4["D"].get<float>();
1512  log<text_log>("Quad 4 set points: " + std::to_string(m_setx4) + " " + std::to_string(m_sety4) + " " + std::to_string(m_setD4));
1513  }
1514 
1515  if(m_setPointSource == USEUSERSET) shmimMonitorT::m_restart = true;
1516  }
1517 
1518  return 0;
1519 }
1520 
1521 INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_refmode)(const pcf::IndiProperty & ipRecv)
1522 {
1523  if(ipRecv.getName() != m_indiP_refmode.getName())
1524  {
1525  log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1526  return -1;
1527  }
1528 
1529  if(ipRecv.find("default"))
1530  {
1531  if( ipRecv["default"].getSwitchState() == pcf::IndiElement::On)
1532  {
1533  if( m_setPointSource != USEDEFSET)
1534  {
1535  log<text_log>("using default reference.", logPrio::LOG_NOTICE);
1536  m_setPointSource = USEDEFSET;
1537  shmimMonitorT::m_restart = true;
1538  return 0;
1539  }
1540  }
1541  }
1542  if(ipRecv.find("refim"))
1543  {
1544  if( ipRecv["refim"].getSwitchState() == pcf::IndiElement::On)
1545  {
1546  if( m_setPointSource != USEREFIM)
1547  {
1548  log<text_log>("using reference image.", logPrio::LOG_NOTICE);
1549  m_setPointSource = USEREFIM;
1550  shmimMonitorT::m_restart = true;
1551  return 0;
1552  }
1553  }
1554  }
1555  if(ipRecv.find("user"))
1556  {
1557  if( ipRecv["user"].getSwitchState() == pcf::IndiElement::On)
1558  {
1559  if( m_setPointSource != USEUSERSET)
1560  {
1561  log<text_log>("using user image.", logPrio::LOG_NOTICE);
1562  m_setPointSource = USEUSERSET;
1563  shmimMonitorT::m_restart = true;
1564  return 0;
1565  }
1566  }
1567  }
1568 
1569  return 0;
1570 }
1571 
1572 inline
1574 {
1576 }
1577 
1578 inline
1580 {
1581  return recordFGTimings(true);
1582 }
1583 
1584 } //namespace app
1585 } //namespace MagAOX
1586 
1587 #endif //pupilFit_hpp
#define IMAGESTRUCT_FLOAT
Definition: ImageStruct.hpp:22
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
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:2877
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:2352
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
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:2321
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
Definition: MagAOXApp.hpp:537
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
Definition: MagAOXApp.hpp:2901
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
Definition: MagAOXApp.hpp:1590
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:2294
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
Definition: MagAOXApp.hpp:2437
std::mutex m_indiMutex
Mutex for locking INDI communications.
Definition: MagAOXApp.hpp:540
int createStandardIndiSelectionSw(pcf::IndiProperty &prop, const std::string &name, const std::vector< std::string > &elements, const std::vector< std::string > &elementLabels, const std::string &label="", const std::string &group="")
Create a standard R/W INDI selection (one of many) switch with vector of elements and element labels.
Definition: MagAOXApp.hpp:2383
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
int appShutdown()
Shuts down the framegrabber thread.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
uint8_t m_dataType
The ImageStreamIO type code.
int appLogic()
Checks the framegrabber thread.
uint32_t m_height
The height of the image, once deinterlaced etc.
uint32_t m_width
The width of the images in the stream.
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.
std::string m_shmimName
The name of the shared memory image, is used in /tmp/<shmimName>.im.shm. Derived classes should set a...
int appShutdown()
Shuts down the shmimMonitor thread.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_restart
Flag indicating tha the shared memory should be reinitialized.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
The MagAO-X Pyramid Pupil Fitter.
Definition: pupilFit.hpp:55
virtual int appShutdown()
Shutdown the app.
Definition: pupilFit.hpp:772
~pupilFit() noexcept
D'tor, declared and defined for noexcept.
Definition: pupilFit.hpp:452
pcf::IndiProperty m_indiP_quad1
Definition: pupilFit.hpp:415
pcf::IndiProperty m_indiP_numPupils
Definition: pupilFit.hpp:413
pcf::IndiProperty m_indiP_quad2
Definition: pupilFit.hpp:416
mx::improc::eigenImage< float > m_fitIm
Definition: pupilFit.hpp:103
INDI_NEWCALLBACK_DECL(pupilFit, m_indiP_refmode)
int m_numPupils
The number of pupils. Default is 4. 3 is also supported.
Definition: pupilFit.hpp:99
friend class pupilFit_test
Definition: pupilFit.hpp:57
pcf::IndiProperty m_indiP_refmode
Definition: pupilFit.hpp:428
INDI_NEWCALLBACK_DECL(pupilFit, m_indiP_update)
std::string m_edgeShmimName
The name of the image stream for the edge images. Default is camwfs_edge.
Definition: pupilFit.hpp:95
mx::improc::eigenImage< float > m_refIm
Definition: pupilFit.hpp:102
int processImage(void *curr_src, const dev::shmimT &)
Definition: pupilFit.hpp:915
INDI_NEWCALLBACK_DECL(pupilFit, m_indiP_thresh)
dev::shmimMonitor< pupilFit, refShmimT > refShmimMonitorT
Definition: pupilFit.hpp:69
dev::shmimMonitor< pupilFit > shmimMonitorT
Definition: pupilFit.hpp:67
virtual int appLogic()
Implementation of the FSM for pupilFit.
Definition: pupilFit.hpp:715
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
Definition: pupilFit.hpp:1347
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber these images can not be flipped
Definition: pupilFit.hpp:84
float realT
Floating point type in which to do all calculations.
Definition: pupilFit.hpp:78
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
Definition: pupilFit.hpp:1310
pcf::IndiProperty m_indiP_quad3
Definition: pupilFit.hpp:417
virtual int appStartup()
Startup function.
Definition: pupilFit.hpp:544
pcf::IndiProperty m_indiP_averaging
Definition: pupilFit.hpp:410
INDI_NEWCALLBACK_DECL(pupilFit, m_indiP_reload)
virtual void loadConfig()
Definition: pupilFit.hpp:538
dev::frameGrabber< pupilFit > frameGrabberT
Definition: pupilFit.hpp:72
pcf::IndiProperty m_indiP_avg
Definition: pupilFit.hpp:420
pupilFitter< realT > m_fitter
Definition: pupilFit.hpp:106
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition: pupilFit.hpp:501
pcf::IndiProperty m_indiP_thresh
Definition: pupilFit.hpp:406
pcf::IndiProperty m_indiP_reload
Definition: pupilFit.hpp:422
pcf::IndiProperty m_indiP_quad4
Definition: pupilFit.hpp:418
dev::telemeter< pupilFit > telemeterT
Definition: pupilFit.hpp:75
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
Definition: pupilFit.hpp:1316
float fps()
Implementation of the framegrabber fps interface.
Definition: pupilFit.hpp:365
int reconfig()
Implementation of the framegrabber reconfig interface.
Definition: pupilFit.hpp:1357
std::string m_threshShmimName
The name of the image stream for the thresholded images. Default is camwfs_thresh.
Definition: pupilFit.hpp:94
pcf::IndiProperty m_indiP_update
Definition: pupilFit.hpp:425
bool m_refUpdated
Flag set if the online reference update is used.
Definition: pupilFit.hpp:148
int allocate(const dev::shmimT &)
Definition: pupilFit.hpp:783
INDI_NEWCALLBACK_DECL(pupilFit, m_indiP_averaging)
sem_t m_smSemaphore
Semaphore used to synchronize the fg thread and the sm thread.
Definition: pupilFit.hpp:345
pupilFit()
Default c'tor.
Definition: pupilFit.hpp:445
virtual void setupConfig()
Definition: pupilFit.hpp:466
int recordTelem(const telem_fgtimings *)
Definition: pupilFit.hpp:1579
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
Definition: pupilFit.hpp:1298
mx::improc::eigenImage< float > m_edgeIm
Definition: pupilFit.hpp:104
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
Definition: indiMacros.hpp:207
@ OPERATING
The device is operating, other than homing.
Definition: stateCodes.hpp:50
#define INDI_IDLE
Definition: indiUtils.hpp:28
#define INDI_BUSY
Definition: indiUtils.hpp:30
std::ostream & cerr()
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:206
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
Definition: acesxeCtrl.hpp:687
Definition: dm.hpp:24
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Definition: logPriority.hpp:40
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
Definition: logPriority.hpp:46
#define USEDEFSET
Definition: pupilFit.hpp:46
#define USEREFIM
Definition: pupilFit.hpp:47
#define USEUSERSET
Definition: pupilFit.hpp:48
The MagAO-X Pyramid Pupil Fitter class header.
A device which saves telemetry.
Definition: telemeter.hpp:52
int appShutdown()
Perform telemeter application shutdown.
Definition: telemeter.hpp:259
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
Definition: telemeter.hpp:208
int appLogic()
Perform telemeter application logic.
Definition: telemeter.hpp:253
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
Definition: telemeter.hpp:195
int appStartup()
Starts the telemetry log thread.
Definition: telemeter.hpp:226
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:266
Struct to perform centration and measure diameter of Pyramid pupils.
Definition: pupilFitter.hpp:23
static std::string indiPrefix()
Definition: pupilFit.hpp:40
static std::string configSection()
Definition: pupilFit.hpp:35
Software ERR log entry.
Log entry recording framegrabber timings.