API
 
Loading...
Searching...
No Matches
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
28namespace MagAOX
29{
30namespace app
31{
32
33struct 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 */
54class 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>;
61 friend class dev::frameGrabber<pupilFit>;
62
63 friend class dev::telemeter<pupilFit>;
64
65public:
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
88protected:
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
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};
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};
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};
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};
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};
270
271 double m_avgyAll_accum {0};
273
274 double m_avgDAll_accum {0};
276
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
292public:
293 /// Default c'tor.
294 pupilFit();
295
296 /// D'tor, declared and defined for 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,
339 );
340
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
347public:
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 */
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 */
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
400protected:
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
444inline
445pupilFit::pupilFit() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
446{
448 return;
449}
450
451inline
453{
455 {
457 }
458
460 {
462 }
463}
464
465inline
467{
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
500inline
501int pupilFit::loadConfigImpl( mx::app::appConfigurator & _config )
502{
503 shmimMonitorT::m_shmimName = "camwfs_avg";
507
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
537inline
539{
540 loadConfigImpl(config);
541}
542
543inline
545{
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
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 {
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, "bg", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "background");
599 indi::addNumberElement<float>( m_indiP_quad1, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
600 m_indiP_quad1["set-x"] = m_setx1;
601 indi::addNumberElement<float>( m_indiP_quad1, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
602 m_indiP_quad1["set-y"] = m_sety1;
603 indi::addNumberElement<float>( m_indiP_quad1, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
604 m_indiP_quad1["set-D"] = m_setD1;
605
607
608 createROIndiNumber( m_indiP_quad2, "quadrant2", "Quadrant 2");
609 indi::addNumberElement<float>( m_indiP_quad2, "x", 0, 59, 0, "%0.2f", "center x");
610 indi::addNumberElement<float>( m_indiP_quad2, "dx", 0, 59, 0, "%0.2f", "delta-x");
611 indi::addNumberElement<float>( m_indiP_quad2, "y", 0, 59, 0, "%0.2f", "center y");
612 indi::addNumberElement<float>( m_indiP_quad2, "dy", 0, 59, 0, "%0.2f", "delta-y");
613 indi::addNumberElement<float>( m_indiP_quad2, "D", 0, 59, 0, "%0.2f", "diameter");
614 indi::addNumberElement<float>( m_indiP_quad2, "dD", 0, 59, 0, "%0.2f", "delta-D");
615 indi::addNumberElement<float>( m_indiP_quad2, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
616 indi::addNumberElement<float>( m_indiP_quad2, "bg", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "background");
617 indi::addNumberElement<float>( m_indiP_quad2, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
618 m_indiP_quad2["set-x"] = m_setx2;
619 indi::addNumberElement<float>( m_indiP_quad2, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
620 m_indiP_quad2["set-y"] = m_sety2;
621 indi::addNumberElement<float>( m_indiP_quad2, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
622 m_indiP_quad2["set-D"] = m_setD2;
624
625 createROIndiNumber( m_indiP_quad3, "quadrant3", "Quadrant 3");
626 indi::addNumberElement<float>( m_indiP_quad3, "x", 0, 59, 0, "%0.2f", "center x");
627 indi::addNumberElement<float>( m_indiP_quad3, "dx", 0, 59, 0, "%0.2f", "delta-x");
628 indi::addNumberElement<float>( m_indiP_quad3, "y", 0, 59, 0, "%0.2f", "center y");
629 indi::addNumberElement<float>( m_indiP_quad3, "dy", 0, 59, 0, "%0.2f", "delta-y");
630 indi::addNumberElement<float>( m_indiP_quad3, "D", 0, 59, 0, "%0.2f", "diameter");
631 indi::addNumberElement<float>( m_indiP_quad3, "dD", 0, 59, 0, "%0.2f", "delta-D");
632 indi::addNumberElement<float>( m_indiP_quad3, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
633 indi::addNumberElement<float>( m_indiP_quad3, "bg", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "background");
634 indi::addNumberElement<float>( m_indiP_quad3, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
635 m_indiP_quad3["set-x"] = m_setx3;
636 indi::addNumberElement<float>( m_indiP_quad3, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
637 m_indiP_quad3["set-y"] = m_sety3;
638 indi::addNumberElement<float>( m_indiP_quad3, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
639 m_indiP_quad3["set-D"] = m_setD3;
641
642 if(m_numPupils != 3)
643 {
644 createROIndiNumber( m_indiP_quad4, "quadrant4", "Quadrant 4");
645 indi::addNumberElement<float>( m_indiP_quad4, "x", 0, 59, 0, "%0.2f", "center x");
646 indi::addNumberElement<float>( m_indiP_quad4, "dx", 0, 59, 0, "%0.2f", "delta-x");
647 indi::addNumberElement<float>( m_indiP_quad4, "y", 0, 59, 0, "%0.2f", "center y");
648 indi::addNumberElement<float>( m_indiP_quad4, "dy", 0, 59, 0, "%0.2f", "delta-y");
649 indi::addNumberElement<float>( m_indiP_quad4, "D", 0, 59, 0, "%0.2f", "diameter");
650 indi::addNumberElement<float>( m_indiP_quad4, "dD", 0, 59, 0, "%0.2f", "delta-D");
651 indi::addNumberElement<float>( m_indiP_quad4, "med", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "flux");
652 indi::addNumberElement<float>( m_indiP_quad4, "bg", 0, std::numeric_limits<uint16_t>::max(), 0, "%0.1f", "background");
653 indi::addNumberElement<float>( m_indiP_quad4, "set-x", 0, 59, 0, "%0.2f", "set pt. center x");
654 m_indiP_quad4["set-x"] = m_setx4;
655 indi::addNumberElement<float>( m_indiP_quad4, "set-y", 0, 59, 0, "%0.2f", "set pt. center x");
656 m_indiP_quad4["set-y"] = m_sety4;
657 indi::addNumberElement<float>( m_indiP_quad4, "set-D", 0, 59, 0, "%0.2f", "set pt. diameter");
658 m_indiP_quad4["set-D"] = m_setD4;
660 }
661
662 createROIndiNumber( m_indiP_avg, "average", "Average");
663 indi::addNumberElement<float>( m_indiP_avg, "x", 0, 59, 0, "%0.2f", "center x");
664 indi::addNumberElement<float>( m_indiP_avg, "dx", 0, 59, 0, "%0.2f", "delta-x");
665 indi::addNumberElement<float>( m_indiP_avg, "y", 0, 59, 0, "%0.2f", "center y");
666 indi::addNumberElement<float>( m_indiP_avg, "dy", 0, 59, 0, "%0.2f", "delta-y");
667 indi::addNumberElement<float>( m_indiP_avg, "D", 0, 59, 0, "%0.2f", "diameter");
668 indi::addNumberElement<float>( m_indiP_avg, "dD", 0, 59, 0, "%0.2f", "delta-D");
670
671 createStandardIndiRequestSw( m_indiP_reload, "setpt_reload", "Reload Calibration");
672 m_indiP_reload["request"].set(pcf::IndiElement::Off);
674 {
676 return -1;
677 }
678
679 createStandardIndiRequestSw( m_indiP_update, "setpt_current", "Set Reference");
680 m_indiP_update["request"].set(pcf::IndiElement::Off);
682 {
684 return -1;
685 }
686
687 createStandardIndiSelectionSw( m_indiP_refmode, "setpt_mode", {"default", "refim", "user"}, "Reference Mode");
689 {
690 m_indiP_refmode["default"].set(pcf::IndiElement::Off);
691 m_indiP_refmode["refim"].set(pcf::IndiElement::On);
692 m_indiP_refmode["user"].set(pcf::IndiElement::Off);
693 }
695 {
696 m_indiP_refmode["default"].set(pcf::IndiElement::Off);
697 m_indiP_refmode["refim"].set(pcf::IndiElement::Off);
698 m_indiP_refmode["user"].set(pcf::IndiElement::On);
699 }
700 else
701 {
702 m_indiP_refmode["default"].set(pcf::IndiElement::On);
703 m_indiP_refmode["refim"].set(pcf::IndiElement::Off);
704 m_indiP_refmode["user"].set(pcf::IndiElement::Off);
705 }
706
708 {
710 return -1;
711 }
712
714
715 return 0;
716}
717
718inline
720{
721 if( shmimMonitorT::appLogic() < 0)
722 {
723 return log<software_error,-1>({__FILE__,__LINE__});
724 }
725
727 {
728 return log<software_error,-1>({__FILE__,__LINE__});
729 }
730
731 if( frameGrabberT::appLogic() < 0)
732 {
733 return log<software_error,-1>({__FILE__,__LINE__});
734 }
735
736 if( telemeterT::appLogic() < 0)
737 {
738 return log<software_error,-1>({__FILE__,__LINE__});
739 }
740
741 std::lock_guard<std::mutex> guard(m_indiMutex);
744
746 {
747 updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::Off);
748 updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::On);
749 updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::Off);
750 }
751 else if(m_setPointSource == USEUSERSET)
752 {
753 updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::Off);
754 updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::Off);
755 updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::On);
756 }
757 else
758 {
759 updateSwitchIfChanged(m_indiP_refmode, "default", pcf::IndiElement::On);
760 updateSwitchIfChanged(m_indiP_refmode, "refim", pcf::IndiElement::Off);
761 updateSwitchIfChanged(m_indiP_refmode, "user", pcf::IndiElement::Off);
762 }
763
766
768 {
770 }
771
772 return 0;
773}
774
775inline
785
786inline
788{
789 static_cast<void>(dummy);
790
791 std::lock_guard<std::mutex> guard(m_indiMutex);
792
795
796 m_fitter.m_numPupils = m_numPupils;
798 m_fitter.m_thresh = m_threshold;
799
801 {
802 mx::improc::eigenImage<float> refim, refedge;
803 refim = m_refIm; //cuz it's modified by fitter.
804 if(m_fitter.fit(refim, refedge) < 0)
805 {
806 return log<software_error, -1>({__FILE__, __LINE__, "error from fitter for reference"});
807 }
808
809 m_setx1 = m_fitter.m_avgx[0];
810 m_sety1 = m_fitter.m_avgy[0];
811 m_setD1 = 2*m_fitter.m_avgr[0];
812
813 m_setx2 = m_fitter.m_avgx[1];
814 m_sety2 = m_fitter.m_avgy[1];
815 m_setD2 = 2*m_fitter.m_avgr[1];
816
817 m_setx3 = m_fitter.m_avgx[2];
818 m_sety3 = m_fitter.m_avgy[2];
819 m_setD3 = 2*m_fitter.m_avgr[2];
820
821 m_setx4 = m_fitter.m_avgx[3];
822 m_sety4 = m_fitter.m_avgy[3];
823 m_setD4 = 2*m_fitter.m_avgr[3];
824
825 log<text_log>("Fit to reference image: ");
826 log<text_log>("Quad 1 set points: " + std::to_string(m_setx1) + " " + std::to_string(m_sety1) + " " + std::to_string(m_setD1));
827 log<text_log>("Quad 2 set points: " + std::to_string(m_setx2) + " " + std::to_string(m_sety2) + " " + std::to_string(m_setD2));
828 log<text_log>("Quad 3 set points: " + std::to_string(m_setx3) + " " + std::to_string(m_sety3) + " " + std::to_string(m_setD3));
829 log<text_log>("Quad 4 set points: " + std::to_string(m_setx4) + " " + std::to_string(m_sety4) + " " + std::to_string(m_setD4));
830 }
831 else
832 {
834 {
835 if(m_refIm.rows()!=0 || m_refIm.cols() != 0) //only complain if the ref image has been loaded
836 {
837 log<text_log>("Reference image size does not match", logPrio::LOG_ERROR);
838 }
839 }
840
842 {
846
850
854
855 if(m_numPupils == 4)
856 {
860 }
861 log<text_log>("Using user set-points");
862
863 }
864 else
865 {
869
873
877
878 if(m_numPupils == 4)
879 {
883 }
884 log<text_log>("Set default set-points");
885 }
886 }
887
888 uint32_t imsize[3];
891 imsize[2] = 1;
892
894 {
897 }
898
900 {
902 m_edgeShmimConnected = false;
903 }
904
907
910
912 {
913 }
914
915 return 0;
916}
917
918inline
919int pupilFit::processImage( void* curr_src,
920 const dev::shmimT & dummy
921 )
922{
923 static_cast<void>(dummy);
924
926 {
927 m_fitIm.data()[nn] = ((float*)curr_src) [nn];
928 }
929
930 m_fitter.m_thresh = m_threshold;
931
933
934
935 {//mutex scope
936
937 std::lock_guard<std::mutex> guard(m_indiMutex);
938 m_indiP_quad1["set-x"].set(m_setx1);
939 m_indiP_quad1["x"].set(m_fitter.m_avgx[0]);
940 m_indiP_quad1["dx"].set(m_fitter.m_avgx[0]-m_setx1);
941 m_indiP_quad1["set-y"].set(m_sety1);
942 m_indiP_quad1["y"].set(m_fitter.m_avgy[0]);
943 m_indiP_quad1["dy"].set(m_fitter.m_avgy[0]-m_sety1);
944 m_indiP_quad1["set-D"].set(m_setD1);
945 m_indiP_quad1["D"].set(2*m_fitter.m_avgr[0]);
946 m_indiP_quad1["dD"].set(2*m_fitter.m_avgr[0]-m_setD1);
947 m_indiP_quad1["med"].set(m_fitter.m_med[0]);
948 m_indiP_quad1["bg"].set(m_fitter.m_bg[0]);
949 m_indiP_quad1.setState (INDI_BUSY);
950 m_indiDriver->sendSetProperty (m_indiP_quad1);
951
952 m_indiP_quad2["set-x"].set(m_setx2);
953 m_indiP_quad2["x"].set(m_fitter.m_avgx[1]);
954 m_indiP_quad2["dx"].set(m_fitter.m_avgx[1]-m_setx2);
955 m_indiP_quad2["set-y"].set(m_sety2);
956 m_indiP_quad2["y"].set(m_fitter.m_avgy[1]);
957 m_indiP_quad2["dy"].set(m_fitter.m_avgy[1]-m_sety2);
958 m_indiP_quad2["set-D"].set(m_setD2);
959 m_indiP_quad2["D"].set(2*m_fitter.m_avgr[1]);
960 m_indiP_quad2["dD"].set(2*m_fitter.m_avgr[1]-m_setD2);
961 m_indiP_quad2["med"].set(m_fitter.m_med[1]);
962 m_indiP_quad2["bg"].set(m_fitter.m_bg[1]);
963 m_indiP_quad2.setState (INDI_BUSY);
964 m_indiDriver->sendSetProperty (m_indiP_quad2);
965
966 m_indiP_quad3["set-x"].set(m_setx3);
967 m_indiP_quad3["x"].set(m_fitter.m_avgx[2]);
968 m_indiP_quad3["dx"].set(m_fitter.m_avgx[2]-m_setx3);
969 m_indiP_quad3["set-y"].set(m_sety3);
970 m_indiP_quad3["y"].set(m_fitter.m_avgy[2]);
971 m_indiP_quad3["dy"].set(m_fitter.m_avgy[2]-m_sety3);
972 m_indiP_quad3["set-D"].set(m_setD3);
973 m_indiP_quad3["D"].set(2*m_fitter.m_avgr[2]);
974 m_indiP_quad3["dD"].set(2*m_fitter.m_avgr[2]-m_setD3);
975 m_indiP_quad3["med"].set(m_fitter.m_med[2]);
976 m_indiP_quad3["bg"].set(m_fitter.m_bg[2]);
977 m_indiP_quad3.setState (INDI_BUSY);
978 m_indiDriver->sendSetProperty (m_indiP_quad3);
979
980 if(m_numPupils == 3)
981 {
982 m_indiP_avg["x"].set(.333*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2]));
983 m_indiP_avg["y"].set(.333*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2]));
984 m_indiP_avg["D"].set(.667*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2]));
985
986 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);
987 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);
988
989
990 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));
991 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));
992 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));
993 }
994 else
995 {
996 m_indiP_quad4["set-x"].set(m_setx4);
997 m_indiP_quad4["x"].set(m_fitter.m_avgx[3]);
998 m_indiP_quad4["dx"].set(m_fitter.m_avgx[3]-m_setx4);
999 m_indiP_quad4["set-y"].set(m_sety4);
1000 m_indiP_quad4["y"].set(m_fitter.m_avgy[3]);
1001 m_indiP_quad4["dy"].set(m_fitter.m_avgy[3]-m_sety4);
1002 m_indiP_quad4["set-D"].set(m_setD4);
1003 m_indiP_quad4["D"].set(2*m_fitter.m_avgr[3]);
1004 m_indiP_quad4["dD"].set(2*m_fitter.m_avgr[3]-m_setD4);
1005 m_indiP_quad4["med"].set(m_fitter.m_med[3]);
1006 m_indiP_quad4["bg"].set(m_fitter.m_bg[3]);
1007 m_indiP_quad4.setState (INDI_BUSY);
1008 m_indiDriver->sendSetProperty (m_indiP_quad4);
1009
1010 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]));
1011 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]));
1012 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]));
1013
1014 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);
1015 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);
1016
1017 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));
1018 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));
1019 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));
1020 m_indiDriver->sendSetProperty (m_indiP_avg);
1021
1022 }
1023
1024 }
1025
1026 //signal framegrabber
1027//Now tell the f.g. to get going
1028 m_updated = true;
1029 if(sem_post(&m_smSemaphore) < 0)
1030 {
1031 log<software_critical>({__FILE__, __LINE__, errno, 0, "Error posting to semaphore"});
1032 return -1;
1033 }
1034
1035
1036 if(m_averaging)
1037 {
1038 ++m_navg;
1039
1040 m_avgx1_accum += m_fitter.m_avgx[0];
1041 m_avgx1sq_accum += m_fitter.m_avgx[0]*m_fitter.m_avgx[0];
1042
1043 m_avgy1_accum += m_fitter.m_avgy[0];
1044 m_avgy1sq_accum += m_fitter.m_avgy[0]*m_fitter.m_avgy[0];
1045
1046 m_avgD1_accum += 2*m_fitter.m_avgr[0];
1047 m_avgD1sq_accum += 4*m_fitter.m_avgr[0]*m_fitter.m_avgr[0];
1048
1049 m_avgmed1_accum += m_fitter.m_med[0];
1050 m_avgmed1sq_accum += m_fitter.m_med[0]*m_fitter.m_med[0];
1051
1054
1057
1060
1063
1064 m_avgx2_accum += m_fitter.m_avgx[1];
1065 m_avgx2sq_accum += m_fitter.m_avgx[1]*m_fitter.m_avgx[1];
1066
1067 m_avgy2_accum += m_fitter.m_avgy[1];
1068 m_avgy2sq_accum += m_fitter.m_avgy[1]*m_fitter.m_avgy[1];
1069
1070 m_avgD2_accum += 2*m_fitter.m_avgr[1];
1071 m_avgD2sq_accum += 4*m_fitter.m_avgr[1]*m_fitter.m_avgr[1];
1072
1073 m_avgmed2_accum += m_fitter.m_med[1];
1074 m_avgmed2sq_accum += m_fitter.m_med[1]*m_fitter.m_med[1];
1075
1078
1081
1084
1087
1088
1089
1090 m_avgx3_accum += m_fitter.m_avgx[2];
1091 m_avgx3sq_accum += m_fitter.m_avgx[2]*m_fitter.m_avgx[2];
1092
1093 m_avgy3_accum += m_fitter.m_avgy[2];
1094 m_avgy3sq_accum += m_fitter.m_avgy[2]*m_fitter.m_avgy[2];
1095
1096 m_avgD3_accum += 2*m_fitter.m_avgr[2];
1097 m_avgD3sq_accum += 4*m_fitter.m_avgr[2]*m_fitter.m_avgr[2];
1098
1099 m_avgmed3_accum += m_fitter.m_med[2];
1100 m_avgmed3sq_accum += m_fitter.m_med[2]*m_fitter.m_med[2];
1101
1104
1107
1110
1113
1114 if(m_numPupils == 3)
1115 {
1116 double tmp = 0.333*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1119
1120 tmp = 0.333*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]);
1123
1124 tmp = 2*0.333*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]);
1127
1128 tmp = 0.333*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]);
1131
1134
1137
1140
1143
1144
1145 std::cerr << "****************************************************************\n";
1146 std::cerr << "Averaged: " << m_navg << "\n";
1147 std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1148 std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1149 std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1150 std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1151 std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1152 std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1153 std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1154 std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1155 std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1156 std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1157 std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1158 std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1159 std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1160 std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1161 std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1162 std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1163 }
1164 else
1165 {
1166 m_avgx4_accum += m_fitter.m_avgx[3];
1167 m_avgx4sq_accum += m_fitter.m_avgx[3]*m_fitter.m_avgx[3];
1168
1169 m_avgy4_accum += m_fitter.m_avgy[3];
1170 m_avgy4sq_accum += m_fitter.m_avgy[3]*m_fitter.m_avgy[3];
1171
1172 m_avgD4_accum += 2*m_fitter.m_avgr[3];
1173 m_avgD4sq_accum += 4*m_fitter.m_avgr[3]*m_fitter.m_avgr[3];
1174
1175 m_avgmed4_accum += m_fitter.m_med[3];
1176 m_avgmed4sq_accum += m_fitter.m_med[3]*m_fitter.m_med[3];
1177
1180
1183
1186
1189
1190
1191 double tmp = 0.25*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1194
1195 tmp = 0.25*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]+m_fitter.m_avgy[3]);
1198
1199 tmp = 2*0.25*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]+m_fitter.m_avgr[3]);
1202
1203 tmp = 0.25*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]+m_fitter.m_med[3]);
1206
1209
1212
1215
1218
1219
1220 std::cerr << "****************************************************************\n";
1221 std::cerr << "Averaged: " << m_navg << "\n";
1222 std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1223 std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1224 std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1225 std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1226 std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1227 std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1228 std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1229 std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1230 std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1231 std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1232 std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1233 std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1234 std::cerr << "Average x4: " << m_avgx4 << " +/- " << sqrt(m_varx4) << "\n";
1235 std::cerr << "Average y4: " << m_avgy4 << " +/- " << sqrt(m_vary4) << "\n";
1236 std::cerr << "Average D4: " << m_avgD4 << " +/- " << sqrt(m_varD4) << "\n";
1237 std::cerr << "Average med4: " << m_avgmed4 << " +/- " << sqrt(m_varmed4) << "\n\n";
1238 std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1239 std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1240 std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1241 std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1242 }
1243 }
1244
1245 m_threshShmim.md->write=1;
1246 m_edgeShmim.md->write=1;
1247
1249 m_edgeShmim.md->writetime = m_threshShmim.md->writetime;
1250
1251 m_threshShmim.md->atime = m_threshShmim.md->writetime;
1252 m_edgeShmim.md->atime = m_threshShmim.md->writetime;
1253
1254 m_threshShmim.md->cnt0++;
1255 m_edgeShmim.md->cnt0++;
1256
1257 memcpy(m_threshShmim.array.raw, m_fitIm.data(), m_fitIm.rows()*m_fitIm.cols()*sizeof(float));
1258 memcpy(m_edgeShmim.array.raw, m_edgeIm.data(), m_edgeIm.rows()*m_edgeIm.cols()*sizeof(float));
1259
1260 m_threshShmim.md->write=0;
1261 m_edgeShmim.md->write=0;
1262
1265
1266 return 0;
1267}
1268
1269inline
1271{
1272 static_cast<void>(dummy);
1273
1274 std::lock_guard<std::mutex> guard(m_indiMutex);
1275
1277 {
1278 return log<software_error,-1>({__FILE__, __LINE__, "reference is not float"});
1279 }
1280
1282
1283 return 0;
1284}
1285
1286inline
1287int pupilFit::processImage( void* curr_src,
1288 const refShmimT & dummy
1289 )
1290{
1291 static_cast<void>(dummy);
1292
1293 int npix = 0;
1295 {
1296 m_refIm.data()[nn] = ((float*)curr_src) [nn];
1297 ++npix;
1298 }
1299
1300 log<text_log>("reference updated", logPrio::LOG_NOTICE);
1301
1302 std::cerr << m_refIm.sum() << " " << npix << "\n";
1303
1305
1306 return 0;
1307}
1308
1309inline
1311{
1312 std::unique_lock<std::mutex> lock(m_indiMutex);
1313
1317
1318 return 0;
1319}
1320
1321inline
1323{
1324 return 0;
1325}
1326
1327inline
1329{
1330 timespec ts;
1331
1333 {
1334 log<software_critical>({__FILE__,__LINE__,errno,0,"clock_gettime"});
1335 return -1;
1336 }
1337
1338 ts.tv_sec += 1;
1339
1340 if(sem_timedwait(&m_smSemaphore, &ts) == 0)
1341 {
1342 if( m_updated )
1343 {
1345 return 0;
1346 }
1347 else
1348 {
1349 return 1;
1350 }
1351 }
1352 else
1353 {
1354 return 1;
1355 }
1356}
1357
1358inline
1360{
1361 ((float *) dest)[0] = m_avg_dx;
1362 ((float *) dest)[1] = m_avg_dy;
1363
1364 m_updated = false;
1365 return 0;
1366}
1367
1368inline
1370{
1371 return 0;
1372}
1373
1374INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_thresh)(const pcf::IndiProperty & ipRecv)
1375{
1376 if(ipRecv.getName() != m_indiP_thresh.getName())
1377 {
1378 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1379 return -1;
1380 }
1381
1382 float target;
1383
1384 if( indiTargetUpdate( m_indiP_thresh, target, ipRecv, true) < 0)
1385 {
1386 log<software_error>({__FILE__,__LINE__});
1387 return -1;
1388 }
1389
1390 m_threshold = target;
1391
1392 if(m_setPointSource == USEREFIM) shmimMonitorT::m_restart = true; //need to re-process the reference
1393
1394 log<text_log>("set threshold = " + std::to_string(m_threshold), logPrio::LOG_NOTICE);
1395 return 0;
1396}
1397
1398INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_averaging)(const pcf::IndiProperty & ipRecv)
1399{
1400 if(ipRecv.getName() != m_indiP_averaging.getName())
1401 {
1402 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1403 return -1;
1404 }
1405
1406 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1407 {
1408
1409 m_avgx1_accum = 0;
1410 m_avgx1sq_accum = 0;
1411 m_avgy1_accum = 0;
1412 m_avgy1sq_accum = 0;
1413 m_avgD1_accum = 0;
1414 m_avgD1sq_accum = 0;
1415 m_avgmed1_accum = 0;
1416 m_avgmed1sq_accum = 0;
1417
1418 m_avgx2_accum = 0;
1419 m_avgx2sq_accum = 0;
1420 m_avgy2_accum = 0;
1421 m_avgy2sq_accum = 0;
1422 m_avgD2_accum = 0;
1423 m_avgD2sq_accum = 0;
1424 m_avgmed2_accum = 0;
1425 m_avgmed2sq_accum = 0;
1426
1427 m_avgx3_accum = 0;
1428 m_avgx3sq_accum = 0;
1429 m_avgy3_accum = 0;
1430 m_avgy3sq_accum = 0;
1431 m_avgD3_accum = 0;
1432 m_avgD3sq_accum = 0;
1433 m_avgmed3_accum = 0;
1434 m_avgmed3sq_accum = 0;
1435
1436 m_avgx4_accum = 0;
1437 m_avgx4sq_accum = 0;
1438 m_avgy4_accum = 0;
1439 m_avgy4sq_accum = 0;
1440 m_avgD4_accum = 0;
1441 m_avgD4sq_accum = 0;
1442 m_avgmed4_accum = 0;
1443 m_avgmed4sq_accum = 0;
1444
1445 m_avgxAll_accum = 0;
1446 m_avgxAllsq_accum = 0;
1447 m_avgyAll_accum = 0;
1448 m_avgyAllsq_accum = 0;
1449 m_avgDAll_accum = 0;
1450 m_avgDAllsq_accum = 0;
1451 m_avgmedAll_accum = 0;
1452 m_avgmedAllsq_accum = 0;
1453
1454 m_navg = 0;
1455 m_averaging = true;
1456
1457 updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::On, INDI_BUSY);
1458
1459 log<text_log>("began averaging");
1460
1461 }
1462 else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1463 {
1464 m_averaging = false;
1465 updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1466
1467 log<text_log>("stopped averaging");
1468 }
1469
1470 return 0;
1471}
1472
1473INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_reload)(const pcf::IndiProperty & ipRecv)
1474{
1475 if(ipRecv.getName() != m_indiP_reload.getName())
1476 {
1477 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1478 return -1;
1479 }
1480
1481 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1482 {
1483 log<text_log>("reloading");
1484 shmimMonitorT::m_restart = 1;
1485 }
1486
1487 return 0;
1488}
1489
1490INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_update)(const pcf::IndiProperty & ipRecv)
1491{
1492 if(ipRecv.getName() != m_indiP_update.getName())
1493 {
1494 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1495 return -1;
1496 }
1497
1498 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1499 {
1500 std::lock_guard<std::mutex> guard(m_indiMutex);
1501
1502 m_setx1 = m_indiP_quad1["x"].get<float>();
1503 m_sety1 = m_indiP_quad1["y"].get<float>();
1504 m_setD1 = m_indiP_quad1["D"].get<float>();
1505
1506 m_setx2 = m_indiP_quad2["x"].get<float>();
1507 m_sety2 = m_indiP_quad2["y"].get<float>();
1508 m_setD2 = m_indiP_quad2["D"].get<float>();
1509
1510 m_setx3 = m_indiP_quad3["x"].get<float>();
1511 m_sety3 = m_indiP_quad3["y"].get<float>();
1512 m_setD3 = m_indiP_quad3["D"].get<float>();
1513
1514 log<text_log>("Recorded current set-points: ");
1515 log<text_log>("Quad 1 set points: " + std::to_string(m_setx1) + " " + std::to_string(m_sety1) + " " + std::to_string(m_setD1));
1516 log<text_log>("Quad 2 set points: " + std::to_string(m_setx2) + " " + std::to_string(m_sety2) + " " + std::to_string(m_setD2));
1517 log<text_log>("Quad 3 set points: " + std::to_string(m_setx3) + " " + std::to_string(m_sety3) + " " + std::to_string(m_setD3));
1518
1519 if(m_numPupils == 4)
1520 {
1521 m_setx4 = m_indiP_quad4["x"].get<float>();
1522 m_sety4 = m_indiP_quad4["y"].get<float>();
1523 m_setD4 = m_indiP_quad4["D"].get<float>();
1524 log<text_log>("Quad 4 set points: " + std::to_string(m_setx4) + " " + std::to_string(m_sety4) + " " + std::to_string(m_setD4));
1525 }
1526
1527 if(m_setPointSource == USEUSERSET) shmimMonitorT::m_restart = true;
1528 }
1529
1530 return 0;
1531}
1532
1533INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_refmode)(const pcf::IndiProperty & ipRecv)
1534{
1535 if(ipRecv.getName() != m_indiP_refmode.getName())
1536 {
1537 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1538 return -1;
1539 }
1540
1541 if(ipRecv.find("default"))
1542 {
1543 if( ipRecv["default"].getSwitchState() == pcf::IndiElement::On)
1544 {
1545 if( m_setPointSource != USEDEFSET)
1546 {
1547 log<text_log>("using default reference.", logPrio::LOG_NOTICE);
1548 m_setPointSource = USEDEFSET;
1549 shmimMonitorT::m_restart = true;
1550 return 0;
1551 }
1552 }
1553 }
1554 if(ipRecv.find("refim"))
1555 {
1556 if( ipRecv["refim"].getSwitchState() == pcf::IndiElement::On)
1557 {
1558 if( m_setPointSource != USEREFIM)
1559 {
1560 log<text_log>("using reference image.", logPrio::LOG_NOTICE);
1561 m_setPointSource = USEREFIM;
1562 shmimMonitorT::m_restart = true;
1563 return 0;
1564 }
1565 }
1566 }
1567 if(ipRecv.find("user"))
1568 {
1569 if( ipRecv["user"].getSwitchState() == pcf::IndiElement::On)
1570 {
1571 if( m_setPointSource != USEUSERSET)
1572 {
1573 log<text_log>("using user image.", logPrio::LOG_NOTICE);
1574 m_setPointSource = USEUSERSET;
1575 shmimMonitorT::m_restart = true;
1576 return 0;
1577 }
1578 }
1579 }
1580
1581 return 0;
1582}
1583
1584inline
1589
1590inline
1592{
1593 return recordFGTimings(true);
1594}
1595
1596} //namespace app
1597} //namespace MagAOX
1598
1599#endif //pupilFit_hpp
#define IMAGESTRUCT_FLOAT
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
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.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
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.
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.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
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.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
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.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
The MagAO-X Pyramid Pupil Fitter.
Definition pupilFit.hpp:55
virtual int appShutdown()
Shutdown the app.
Definition pupilFit.hpp:776
~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:919
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:719
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
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.
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.
float fps()
Implementation of the framegrabber fps interface.
Definition pupilFit.hpp:365
int reconfig()
Implementation of the framegrabber reconfig interface.
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:787
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 *)
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
mx::improc::eigenImage< float > m_edgeIm
Definition pupilFit.hpp:104
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
@ OPERATING
The device is operating, other than homing.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_BUSY
Definition indiUtils.hpp:30
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
#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 base class which saves telemetry.
Definition telemeter.hpp:69
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int appStartup()
Starts the telemetry log thread.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Struct to perform centration and measure diameter of Pyramid pupils.
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.