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 float m_defSetx1 {29.5};
115 float m_defSety1 {29.5};
116 float m_defSetD1 {56.0};
117
118 float m_defSetx2 {89.5};
119 float m_defSety2 {29.5};
120 float m_defSetD2 {56.0};
121
122 float m_defSetx3 {29.5};
123 float m_defSety3 {89.5};
124 float m_defSetD3 {56.0};
125
126 float m_defSetx4 {89.5};
127 float m_defSety4 {89.5};
128 float m_defSetD4 {56.0};
129
130 float m_userSetx1 {29.5};
131 float m_userSety1 {29.5};
132 float m_userSetD1 {56.0};
133
134 float m_userSetx2 {89.5};
135 float m_userSety2 {29.5};
136 float m_userSetD2 {56.0};
137
138 float m_userSetx3 {29.5};
139 float m_userSety3 {89.5};
140 float m_userSetD3 {56.0};
141
142 float m_userSetx4 {89.5};
143 float m_userSety4 {89.5};
144 float m_userSetD4 {56.0};
145
147
148 bool m_refUpdated {false}; ///< Flag set if the online reference update is used.
149
150 float m_setx1 {29.5};
151 float m_sety1 {29.5};
152 float m_setD1 {56.0};
153
154 float m_setx2 {89.5};
155 float m_sety2 {29.5};
156 float m_setD2 {56.0};
157
158 float m_setx3 {29.5};
159 float m_sety3 {89.5};
160 float m_setD3 {56.0};
161
162 float m_setx4 {89.5};
163 float m_sety4 {89.5};
164 float m_setD4 {56.0};
165
166 float m_avg_dx {0};
167 float m_avg_dy {0};
168
169 bool m_averaging {false};
170 size_t m_navg {0};
171
172 float m_avgx1_accum {0};
174
175 float m_avgy1_accum {0};
177
178 float m_avgD1_accum {0};
180
183
184 float m_avgx1 {0};
185 float m_varx1 {0};
186
187 float m_avgy1 {0};
188 float m_vary1 {0};
189
190 float m_avgD1 {0};
191 float m_varD1 {0};
192
193 float m_avgmed1 {0};
194 float m_varmed1 {0};
195
196 float m_avgx2_accum {0};
198
199 float m_avgy2_accum {0};
201
202 float m_avgD2_accum {0};
204
207
208 float m_avgx2 {0};
209 float m_varx2 {0};
210
211 float m_avgy2 {0};
212 float m_vary2 {0};
213
214 float m_avgD2 {0};
215 float m_varD2 {0};
216
217 float m_avgmed2 {0};
218 float m_varmed2 {0};
219
220 float m_avgx3_accum {0};
222
223 float m_avgy3_accum {0};
225
226 float m_avgD3_accum {0};
228
231
232 float m_avgx3 {0};
233 float m_varx3 {0};
234
235 float m_avgy3 {0};
236 float m_vary3 {0};
237
238 float m_avgD3 {0};
239 float m_varD3 {0};
240
241 float m_avgmed3 {0};
242 float m_varmed3 {0};
243
244 float m_avgx4_accum {0};
246
247 float m_avgy4_accum {0};
249
250 float m_avgD4_accum {0};
252
255
256 float m_avgx4 {0};
257 float m_varx4 {0};
258
259 float m_avgy4 {0};
260 float m_vary4 {0};
261
262 float m_avgD4 {0};
263 float m_varD4 {0};
264
265 float m_avgmed4 {0};
266 float m_varmed4 {0};
267
270
273
276
279
280 float m_avgxAll {0};
281 float m_varxAll {0};
282
283 float m_avgyAll {0};
284 float m_varyAll {0};
285
286 float m_avgDAll {0};
287 float m_varDAll {0};
288
289 float m_avgmedAll {0};
290 float 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
911
912 return 0;
913}
914
915inline
916int pupilFit::processImage( void* curr_src,
917 const dev::shmimT & dummy
918 )
919{
920 static_cast<void>(dummy);
921
923 {
924 m_fitIm.data()[nn] = (reinterpret_cast<float *>(curr_src)) [nn];
925 }
926
927 m_fitter.m_thresh = m_threshold;
928
930
931
932 {//mutex scope
933
934 std::lock_guard<std::mutex> guard(m_indiMutex);
935 m_indiP_quad1["set-x"].set(m_setx1);
936 m_indiP_quad1["x"].set(m_fitter.m_avgx[0]);
937 m_indiP_quad1["dx"].set(m_fitter.m_avgx[0]-m_setx1);
938 m_indiP_quad1["set-y"].set(m_sety1);
939 m_indiP_quad1["y"].set(m_fitter.m_avgy[0]);
940 m_indiP_quad1["dy"].set(m_fitter.m_avgy[0]-m_sety1);
941 m_indiP_quad1["set-D"].set(m_setD1);
942 m_indiP_quad1["D"].set(2*m_fitter.m_avgr[0]);
943 m_indiP_quad1["dD"].set(2*m_fitter.m_avgr[0]-m_setD1);
944 m_indiP_quad1["med"].set(m_fitter.m_med[0]);
945 m_indiP_quad1["bg"].set(m_fitter.m_bg[0]);
946 m_indiP_quad1.setState (INDI_BUSY);
947 m_indiDriver->sendSetProperty (m_indiP_quad1);
948
949 m_indiP_quad2["set-x"].set(m_setx2);
950 m_indiP_quad2["x"].set(m_fitter.m_avgx[1]);
951 m_indiP_quad2["dx"].set(m_fitter.m_avgx[1]-m_setx2);
952 m_indiP_quad2["set-y"].set(m_sety2);
953 m_indiP_quad2["y"].set(m_fitter.m_avgy[1]);
954 m_indiP_quad2["dy"].set(m_fitter.m_avgy[1]-m_sety2);
955 m_indiP_quad2["set-D"].set(m_setD2);
956 m_indiP_quad2["D"].set(2*m_fitter.m_avgr[1]);
957 m_indiP_quad2["dD"].set(2*m_fitter.m_avgr[1]-m_setD2);
958 m_indiP_quad2["med"].set(m_fitter.m_med[1]);
959 m_indiP_quad2["bg"].set(m_fitter.m_bg[1]);
960 m_indiP_quad2.setState (INDI_BUSY);
961 m_indiDriver->sendSetProperty (m_indiP_quad2);
962
963 m_indiP_quad3["set-x"].set(m_setx3);
964 m_indiP_quad3["x"].set(m_fitter.m_avgx[2]);
965 m_indiP_quad3["dx"].set(m_fitter.m_avgx[2]-m_setx3);
966 m_indiP_quad3["set-y"].set(m_sety3);
967 m_indiP_quad3["y"].set(m_fitter.m_avgy[2]);
968 m_indiP_quad3["dy"].set(m_fitter.m_avgy[2]-m_sety3);
969 m_indiP_quad3["set-D"].set(m_setD3);
970 m_indiP_quad3["D"].set(2*m_fitter.m_avgr[2]);
971 m_indiP_quad3["dD"].set(2*m_fitter.m_avgr[2]-m_setD3);
972 m_indiP_quad3["med"].set(m_fitter.m_med[2]);
973 m_indiP_quad3["bg"].set(m_fitter.m_bg[2]);
974 m_indiP_quad3.setState (INDI_BUSY);
975 m_indiDriver->sendSetProperty (m_indiP_quad3);
976
977 if(m_numPupils == 3)
978 {
979 m_indiP_avg["x"].set(.333*(m_fitter.m_avgx[0] + m_fitter.m_avgx[1] + m_fitter.m_avgx[2]));
980 m_indiP_avg["y"].set(.333*(m_fitter.m_avgy[0] + m_fitter.m_avgy[1] + m_fitter.m_avgy[2]));
981 m_indiP_avg["D"].set(.667*(m_fitter.m_avgr[0] + m_fitter.m_avgr[1] + m_fitter.m_avgr[2]));
982
983 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);
984 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);
985
986
987 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));
988 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));
989 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));
990 }
991 else
992 {
993 m_indiP_quad4["set-x"].set(m_setx4);
994 m_indiP_quad4["x"].set(m_fitter.m_avgx[3]);
995 m_indiP_quad4["dx"].set(m_fitter.m_avgx[3]-m_setx4);
996 m_indiP_quad4["set-y"].set(m_sety4);
997 m_indiP_quad4["y"].set(m_fitter.m_avgy[3]);
998 m_indiP_quad4["dy"].set(m_fitter.m_avgy[3]-m_sety4);
999 m_indiP_quad4["set-D"].set(m_setD4);
1000 m_indiP_quad4["D"].set(2*m_fitter.m_avgr[3]);
1001 m_indiP_quad4["dD"].set(2*m_fitter.m_avgr[3]-m_setD4);
1002 m_indiP_quad4["med"].set(m_fitter.m_med[3]);
1003 m_indiP_quad4["bg"].set(m_fitter.m_bg[3]);
1004 m_indiP_quad4.setState (INDI_BUSY);
1005 m_indiDriver->sendSetProperty (m_indiP_quad4);
1006
1007 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]));
1008 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]));
1009 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]));
1010
1011 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);
1012 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);
1013
1014 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));
1015 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));
1016 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));
1017 m_indiDriver->sendSetProperty (m_indiP_avg);
1018
1019 }
1020
1021 }
1022
1023 //signal framegrabber
1024//Now tell the f.g. to get going
1025 m_updated = true;
1026 if(sem_post(&m_smSemaphore) < 0)
1027 {
1028 log<software_critical>({__FILE__, __LINE__, errno, 0, "Error posting to semaphore"});
1029 return -1;
1030 }
1031
1032
1033 if(m_averaging)
1034 {
1035 ++m_navg;
1036
1037 m_avgx1_accum += m_fitter.m_avgx[0];
1038 m_avgx1sq_accum += m_fitter.m_avgx[0]*m_fitter.m_avgx[0];
1039
1040 m_avgy1_accum += m_fitter.m_avgy[0];
1041 m_avgy1sq_accum += m_fitter.m_avgy[0]*m_fitter.m_avgy[0];
1042
1043 m_avgD1_accum += 2*m_fitter.m_avgr[0];
1044 m_avgD1sq_accum += 4*m_fitter.m_avgr[0]*m_fitter.m_avgr[0];
1045
1046 m_avgmed1_accum += m_fitter.m_med[0];
1047 m_avgmed1sq_accum += m_fitter.m_med[0]*m_fitter.m_med[0];
1048
1051
1054
1057
1060
1061 m_avgx2_accum += m_fitter.m_avgx[1];
1062 m_avgx2sq_accum += m_fitter.m_avgx[1]*m_fitter.m_avgx[1];
1063
1064 m_avgy2_accum += m_fitter.m_avgy[1];
1065 m_avgy2sq_accum += m_fitter.m_avgy[1]*m_fitter.m_avgy[1];
1066
1067 m_avgD2_accum += 2*m_fitter.m_avgr[1];
1068 m_avgD2sq_accum += 4*m_fitter.m_avgr[1]*m_fitter.m_avgr[1];
1069
1070 m_avgmed2_accum += m_fitter.m_med[1];
1071 m_avgmed2sq_accum += m_fitter.m_med[1]*m_fitter.m_med[1];
1072
1075
1078
1081
1084
1085
1086
1087 m_avgx3_accum += m_fitter.m_avgx[2];
1088 m_avgx3sq_accum += m_fitter.m_avgx[2]*m_fitter.m_avgx[2];
1089
1090 m_avgy3_accum += m_fitter.m_avgy[2];
1091 m_avgy3sq_accum += m_fitter.m_avgy[2]*m_fitter.m_avgy[2];
1092
1093 m_avgD3_accum += 2*m_fitter.m_avgr[2];
1094 m_avgD3sq_accum += 4*m_fitter.m_avgr[2]*m_fitter.m_avgr[2];
1095
1096 m_avgmed3_accum += m_fitter.m_med[2];
1097 m_avgmed3sq_accum += m_fitter.m_med[2]*m_fitter.m_med[2];
1098
1101
1104
1107
1110
1111 if(m_numPupils == 3)
1112 {
1113 float tmp = 0.333*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1116
1117 tmp = 0.333*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]);
1120
1121 tmp = 2*0.333*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]);
1124
1125 tmp = 0.333*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]);
1128
1131
1134
1137
1140
1141
1142 std::cerr << "****************************************************************\n";
1143 std::cerr << "Averaged: " << m_navg << "\n";
1144 std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1145 std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1146 std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1147 std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1148 std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1149 std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1150 std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1151 std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1152 std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1153 std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1154 std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1155 std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1156 std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1157 std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1158 std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1159 std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1160 }
1161 else
1162 {
1163 m_avgx4_accum += m_fitter.m_avgx[3];
1164 m_avgx4sq_accum += m_fitter.m_avgx[3]*m_fitter.m_avgx[3];
1165
1166 m_avgy4_accum += m_fitter.m_avgy[3];
1167 m_avgy4sq_accum += m_fitter.m_avgy[3]*m_fitter.m_avgy[3];
1168
1169 m_avgD4_accum += 2*m_fitter.m_avgr[3];
1170 m_avgD4sq_accum += 4*m_fitter.m_avgr[3]*m_fitter.m_avgr[3];
1171
1172 m_avgmed4_accum += m_fitter.m_med[3];
1173 m_avgmed4sq_accum += m_fitter.m_med[3]*m_fitter.m_med[3];
1174
1177
1180
1183
1186
1187
1188 float tmp = 0.25*(m_fitter.m_avgx[0]+m_fitter.m_avgx[1]+m_fitter.m_avgx[2]+m_fitter.m_avgx[3]);
1191
1192 tmp = 0.25*(m_fitter.m_avgy[0]+m_fitter.m_avgy[1]+m_fitter.m_avgy[2]+m_fitter.m_avgy[3]);
1195
1196 tmp = 2*0.25*(m_fitter.m_avgr[0]+m_fitter.m_avgr[1]+m_fitter.m_avgr[2]+m_fitter.m_avgr[3]);
1199
1200 tmp = 0.25*(m_fitter.m_med[0]+m_fitter.m_med[1]+m_fitter.m_med[2]+m_fitter.m_med[3]);
1203
1206
1209
1212
1215
1216
1217 std::cerr << "****************************************************************\n";
1218 std::cerr << "Averaged: " << m_navg << "\n";
1219 std::cerr << "Average x1: " << m_avgx1 << " +/- " << sqrt(m_varx1) << "\n";
1220 std::cerr << "Average y1: " << m_avgy1 << " +/- " << sqrt(m_vary1) << "\n";
1221 std::cerr << "Average D1: " << m_avgD1 << " +/- " << sqrt(m_varD1) << "\n";
1222 std::cerr << "Average med1: " << m_avgmed1 << " +/- " << sqrt(m_varmed1) << "\n\n";
1223 std::cerr << "Average x2: " << m_avgx2 << " +/- " << sqrt(m_varx2) << "\n";
1224 std::cerr << "Average y2: " << m_avgy2 << " +/- " << sqrt(m_vary2) << "\n";
1225 std::cerr << "Average D2: " << m_avgD2 << " +/- " << sqrt(m_varD2) << "\n";
1226 std::cerr << "Average med2: " << m_avgmed2 << " +/- " << sqrt(m_varmed2) << "\n\n";
1227 std::cerr << "Average x3: " << m_avgx3 << " +/- " << sqrt(m_varx3) << "\n";
1228 std::cerr << "Average y3: " << m_avgy3 << " +/- " << sqrt(m_vary3) << "\n";
1229 std::cerr << "Average D3: " << m_avgD3 << " +/- " << sqrt(m_varD3) << "\n";
1230 std::cerr << "Average med3: " << m_avgmed3 << " +/- " << sqrt(m_varmed3) << "\n\n";
1231 std::cerr << "Average x4: " << m_avgx4 << " +/- " << sqrt(m_varx4) << "\n";
1232 std::cerr << "Average y4: " << m_avgy4 << " +/- " << sqrt(m_vary4) << "\n";
1233 std::cerr << "Average D4: " << m_avgD4 << " +/- " << sqrt(m_varD4) << "\n";
1234 std::cerr << "Average med4: " << m_avgmed4 << " +/- " << sqrt(m_varmed4) << "\n\n";
1235 std::cerr << "Average xAll: " << m_avgxAll << " +/- " << sqrt(m_varxAll) << "\n";
1236 std::cerr << "Average yAll: " << m_avgyAll << " +/- " << sqrt(m_varyAll) << "\n";
1237 std::cerr << "Average DAll: " << m_avgDAll << " +/- " << sqrt(m_varDAll) << "\n";
1238 std::cerr << "Average medAll: " << m_avgmedAll << " +/- " << sqrt(m_varmedAll) << "\n\n";
1239 }
1240 }
1241
1242 m_threshShmim.md->write=1;
1243 m_edgeShmim.md->write=1;
1244
1246 m_edgeShmim.md->writetime = m_threshShmim.md->writetime;
1247
1248 m_threshShmim.md->atime = m_threshShmim.md->writetime;
1249 m_edgeShmim.md->atime = m_threshShmim.md->writetime;
1250
1251 m_threshShmim.md->cnt0++;
1252 m_edgeShmim.md->cnt0++;
1253
1254 memcpy(m_threshShmim.array.raw, m_fitIm.data(), m_fitIm.rows()*m_fitIm.cols()*sizeof(float));
1255 memcpy(m_edgeShmim.array.raw, m_edgeIm.data(), m_edgeIm.rows()*m_edgeIm.cols()*sizeof(float));
1256
1257 m_threshShmim.md->write=0;
1258 m_edgeShmim.md->write=0;
1259
1262
1263 return 0;
1264}
1265
1266inline
1268{
1269 static_cast<void>(dummy);
1270
1271 std::lock_guard<std::mutex> guard(m_indiMutex);
1272
1274 {
1275 return log<software_error,-1>({__FILE__, __LINE__, "reference is not float"});
1276 }
1277
1279
1280 return 0;
1281}
1282
1283inline
1284int pupilFit::processImage( void* curr_src,
1285 const refShmimT & dummy
1286 )
1287{
1288 static_cast<void>(dummy);
1289
1290 int npix = 0;
1292 {
1293 m_refIm.data()[nn] = (reinterpret_cast<float *>(curr_src)) [nn];
1294 ++npix;
1295 }
1296
1297 log<text_log>("reference updated", logPrio::LOG_NOTICE);
1298
1299 std::cerr << m_refIm.sum() << " " << npix << "\n";
1300
1302
1303 return 0;
1304}
1305
1306inline
1308{
1309 std::unique_lock<std::mutex> lock(m_indiMutex);
1310
1314
1315 return 0;
1316}
1317
1318inline
1320{
1321 return 0;
1322}
1323
1324inline
1326{
1327 timespec ts;
1328
1330 {
1331 log<software_critical>({__FILE__,__LINE__,errno,0,"clock_gettime"});
1332 return -1;
1333 }
1334
1335 ts.tv_sec += 1;
1336
1337 if(sem_timedwait(&m_smSemaphore, &ts) == 0)
1338 {
1339 if( m_updated )
1340 {
1342 return 0;
1343 }
1344 else
1345 {
1346 return 1;
1347 }
1348 }
1349 else
1350 {
1351 return 1;
1352 }
1353}
1354
1355inline
1357{
1358 (reinterpret_cast<float *>(dest))[0] = m_avg_dx;
1359 (reinterpret_cast<float *>(dest))[1] = m_avg_dy;
1360
1361 m_updated = false;
1362 return 0;
1363}
1364
1365inline
1367{
1368 return 0;
1369}
1370
1371INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_thresh)(const pcf::IndiProperty & ipRecv)
1372{
1373 if(ipRecv.getName() != m_indiP_thresh.getName())
1374 {
1375 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1376 return -1;
1377 }
1378
1379 float target;
1380
1381 if( indiTargetUpdate( m_indiP_thresh, target, ipRecv, true) < 0)
1382 {
1383 log<software_error>({__FILE__,__LINE__});
1384 return -1;
1385 }
1386
1387 m_threshold = target;
1388
1389 if(m_setPointSource == USEREFIM) shmimMonitorT::m_restart = true; //need to re-process the reference
1390
1391 log<text_log>("set threshold = " + std::to_string(m_threshold), logPrio::LOG_NOTICE);
1392 return 0;
1393}
1394
1395INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_averaging)(const pcf::IndiProperty & ipRecv)
1396{
1397 if(ipRecv.getName() != m_indiP_averaging.getName())
1398 {
1399 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1400 return -1;
1401 }
1402
1403 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1404 {
1405
1406 m_avgx1_accum = 0;
1407 m_avgx1sq_accum = 0;
1408 m_avgy1_accum = 0;
1409 m_avgy1sq_accum = 0;
1410 m_avgD1_accum = 0;
1411 m_avgD1sq_accum = 0;
1412 m_avgmed1_accum = 0;
1413 m_avgmed1sq_accum = 0;
1414
1415 m_avgx2_accum = 0;
1416 m_avgx2sq_accum = 0;
1417 m_avgy2_accum = 0;
1418 m_avgy2sq_accum = 0;
1419 m_avgD2_accum = 0;
1420 m_avgD2sq_accum = 0;
1421 m_avgmed2_accum = 0;
1422 m_avgmed2sq_accum = 0;
1423
1424 m_avgx3_accum = 0;
1425 m_avgx3sq_accum = 0;
1426 m_avgy3_accum = 0;
1427 m_avgy3sq_accum = 0;
1428 m_avgD3_accum = 0;
1429 m_avgD3sq_accum = 0;
1430 m_avgmed3_accum = 0;
1431 m_avgmed3sq_accum = 0;
1432
1433 m_avgx4_accum = 0;
1434 m_avgx4sq_accum = 0;
1435 m_avgy4_accum = 0;
1436 m_avgy4sq_accum = 0;
1437 m_avgD4_accum = 0;
1438 m_avgD4sq_accum = 0;
1439 m_avgmed4_accum = 0;
1440 m_avgmed4sq_accum = 0;
1441
1442 m_avgxAll_accum = 0;
1443 m_avgxAllsq_accum = 0;
1444 m_avgyAll_accum = 0;
1445 m_avgyAllsq_accum = 0;
1446 m_avgDAll_accum = 0;
1447 m_avgDAllsq_accum = 0;
1448 m_avgmedAll_accum = 0;
1449 m_avgmedAllsq_accum = 0;
1450
1451 m_navg = 0;
1452 m_averaging = true;
1453
1454 updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::On, INDI_BUSY);
1455
1456 log<text_log>("began averaging");
1457
1458 }
1459 else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1460 {
1461 m_averaging = false;
1462 updateSwitchIfChanged(m_indiP_averaging, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1463
1464 log<text_log>("stopped averaging");
1465 }
1466
1467 return 0;
1468}
1469
1470INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_reload)(const pcf::IndiProperty & ipRecv)
1471{
1472 if(ipRecv.getName() != m_indiP_reload.getName())
1473 {
1474 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1475 return -1;
1476 }
1477
1478 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1479 {
1480 log<text_log>("reloading");
1481 shmimMonitorT::m_restart = 1;
1482 }
1483
1484 return 0;
1485}
1486
1487INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_update)(const pcf::IndiProperty & ipRecv)
1488{
1489 if(ipRecv.getName() != m_indiP_update.getName())
1490 {
1491 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1492 return -1;
1493 }
1494
1495 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1496 {
1497 std::lock_guard<std::mutex> guard(m_indiMutex);
1498
1499 m_setx1 = m_indiP_quad1["x"].get<float>();
1500 m_sety1 = m_indiP_quad1["y"].get<float>();
1501 m_setD1 = m_indiP_quad1["D"].get<float>();
1502
1503 m_setx2 = m_indiP_quad2["x"].get<float>();
1504 m_sety2 = m_indiP_quad2["y"].get<float>();
1505 m_setD2 = m_indiP_quad2["D"].get<float>();
1506
1507 m_setx3 = m_indiP_quad3["x"].get<float>();
1508 m_sety3 = m_indiP_quad3["y"].get<float>();
1509 m_setD3 = m_indiP_quad3["D"].get<float>();
1510
1511 log<text_log>("Recorded current set-points: ");
1512 log<text_log>("Quad 1 set points: " + std::to_string(m_setx1) + " " + std::to_string(m_sety1) + " " + std::to_string(m_setD1));
1513 log<text_log>("Quad 2 set points: " + std::to_string(m_setx2) + " " + std::to_string(m_sety2) + " " + std::to_string(m_setD2));
1514 log<text_log>("Quad 3 set points: " + std::to_string(m_setx3) + " " + std::to_string(m_sety3) + " " + std::to_string(m_setD3));
1515
1516 if(m_numPupils == 4)
1517 {
1518 m_setx4 = m_indiP_quad4["x"].get<float>();
1519 m_sety4 = m_indiP_quad4["y"].get<float>();
1520 m_setD4 = m_indiP_quad4["D"].get<float>();
1521 log<text_log>("Quad 4 set points: " + std::to_string(m_setx4) + " " + std::to_string(m_sety4) + " " + std::to_string(m_setD4));
1522 }
1523
1524 if(m_setPointSource == USEUSERSET) shmimMonitorT::m_restart = true;
1525 }
1526
1527 return 0;
1528}
1529
1530INDI_NEWCALLBACK_DEFN(pupilFit, m_indiP_refmode)(const pcf::IndiProperty & ipRecv)
1531{
1532 if(ipRecv.getName() != m_indiP_refmode.getName())
1533 {
1534 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1535 return -1;
1536 }
1537
1538 if(ipRecv.find("default"))
1539 {
1540 if( ipRecv["default"].getSwitchState() == pcf::IndiElement::On)
1541 {
1542 if( m_setPointSource != USEDEFSET)
1543 {
1544 log<text_log>("using default reference.", logPrio::LOG_NOTICE);
1545 m_setPointSource = USEDEFSET;
1546 shmimMonitorT::m_restart = true;
1547 return 0;
1548 }
1549 }
1550 }
1551 if(ipRecv.find("refim"))
1552 {
1553 if( ipRecv["refim"].getSwitchState() == pcf::IndiElement::On)
1554 {
1555 if( m_setPointSource != USEREFIM)
1556 {
1557 log<text_log>("using reference image.", logPrio::LOG_NOTICE);
1558 m_setPointSource = USEREFIM;
1559 shmimMonitorT::m_restart = true;
1560 return 0;
1561 }
1562 }
1563 }
1564 if(ipRecv.find("user"))
1565 {
1566 if( ipRecv["user"].getSwitchState() == pcf::IndiElement::On)
1567 {
1568 if( m_setPointSource != USEUSERSET)
1569 {
1570 log<text_log>("using user image.", logPrio::LOG_NOTICE);
1571 m_setPointSource = USEUSERSET;
1572 shmimMonitorT::m_restart = true;
1573 return 0;
1574 }
1575 }
1576 }
1577
1578 return 0;
1579}
1580
1581inline
1586
1587inline
1589{
1590 return recordFGTimings(true);
1591}
1592
1593} //namespace app
1594} //namespace MagAOX
1595
1596#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:916
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:27
#define INDI_BUSY
Definition indiUtils.hpp:29
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.