Line data Source code
1 : /** \file psfFit.hpp
2 : * \brief The MagAO-X PSF Fitter application header
3 : *
4 : * \ingroup psfFit_files
5 : */
6 :
7 : #ifndef psfFit_hpp
8 : #define psfFit_hpp
9 :
10 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
11 : #include "../../magaox_git_version.h"
12 :
13 : /** \defgroup psfFit
14 : * \brief The MagAO-X PSF fitter.
15 : *
16 : * <a href="../handbook/operating/software/apps/psfFit.html">Application Documentation</a>
17 : *
18 : * \ingroup apps
19 : *
20 : */
21 :
22 : /** \defgroup psfFit_files
23 : * \ingroup psfFit
24 : */
25 :
26 : namespace MagAOX
27 : {
28 : namespace app
29 : {
30 :
31 : struct darkShmimT
32 : {
33 0 : static std::string configSection()
34 : {
35 0 : return "darkShmim";
36 : };
37 :
38 0 : static std::string indiPrefix()
39 : {
40 0 : return "dark";
41 : };
42 : };
43 :
44 : struct refShmimT
45 : {
46 0 : static std::string configSection()
47 : {
48 0 : return "refShmim";
49 : };
50 :
51 0 : static std::string indiPrefix()
52 : {
53 0 : return "ref";
54 : };
55 : };
56 :
57 : /// The MagAO-X PSF Fitter
58 : /**
59 : * \ingroup psfFit
60 : */
61 : class psfFit : public MagAOXApp<true>,
62 : public dev::shmimMonitor<psfFit>,
63 : public dev::shmimMonitor<psfFit, darkShmimT>,
64 : public dev::shmimMonitor<psfFit, refShmimT>,
65 : public dev::frameGrabber<psfFit>,
66 : public dev::telemeter<psfFit>
67 : {
68 : // Give the test harness access.
69 : friend class psfFit_test;
70 :
71 : friend class dev::shmimMonitor<psfFit>;
72 : friend class dev::shmimMonitor<psfFit, darkShmimT>;
73 : friend class dev::shmimMonitor<psfFit, refShmimT>;
74 : friend class dev::frameGrabber<psfFit>;
75 :
76 : friend class dev::telemeter<psfFit>;
77 :
78 : public:
79 : /// The base shmimMonitor type
80 : typedef dev::shmimMonitor<psfFit> shmimMonitorT;
81 :
82 : /// The dark shmimMonitor type
83 : typedef dev::shmimMonitor<psfFit, darkShmimT> darkShmimMonitorT;
84 :
85 : /// The reference shmimMonitor type
86 : typedef dev::shmimMonitor<psfFit, refShmimT> refShmimMonitorT;
87 :
88 : // The base frameGrabber type
89 : typedef dev::frameGrabber<psfFit> frameGrabberT;
90 :
91 : // The base telemeter type
92 : typedef dev::telemeter<psfFit> telemeterT;
93 :
94 : /// Floating point type in which to do all calculations.
95 : typedef float realT;
96 :
97 : /** \name app::dev Configurations
98 : *@{
99 : */
100 :
101 : static constexpr bool c_frameGrabber_flippable =
102 : false; ///< app:dev config to tell framegrabber these images can not be flipped
103 :
104 : ///@}
105 :
106 : protected:
107 : /** \name Configurable Parameters
108 : *@{
109 : */
110 :
111 : std::string m_fpsDevice; ///< Device name for getting fps to set circular buffer length.
112 : std::string m_fpsProperty{ "fps" }; ///< Property name for getting fps to set circular buffer length.
113 : std::string m_fpsElement{ "current" }; ///< Element name for getting fps to set circular buffer length.
114 :
115 : float m_fpsTol{ 0 }; ///< The tolerance for detecting a change in FPS.
116 :
117 : // shutter a change in shutter state resets stats
118 : std::string m_shutterDevice; ///< Device name for getting shutter state
119 : std::string m_shutterProperty{ "shutter" }; ///< Property name for getting shutter state
120 : std::string m_shutterElement{ "toggle" }; ///< Element name for getting shutter state
121 :
122 : uint16_t m_fitCircBuffMaxLength{ 5 * 10000 }; ///< Maximum length of the latency measurement circular buffers
123 :
124 : float m_fitCircBuffMaxTime{ 5 }; ///< Maximum time of the latency meaurement circular buffers
125 :
126 : float m_deltaPixThresh{ 8 }; /**< Threshold in pixels for skipping frame due to mismatch between max and c.o.l.
127 : Default 2.*/
128 :
129 : float m_sigmaMaxThreshUp{ 5 }; /**< Threshold in rms for skipping frame due to max positive difference from mean
130 : max. Default 5.*/
131 :
132 : float m_fractionMaxThreshDown{ 0.1 }; /**< Threshold in fraction of the mean max for skipping frame due to
133 : drop from mean max. Default 0.1*/
134 :
135 : float m_sigmaPixThresh{ 10 }; /**< Threshold in rms for skipping frame due to max difference from last value.
136 : Example: if this is set to 10, then the pixel postion has to change from -5 sigma
137 : to + 5 sigma to be rejected. Default 10.*/
138 :
139 : ///@}
140 :
141 : mx::improc::eigenImage<float> m_image; ///< Holds the raw image
142 :
143 : mx::improc::eigenImage<float> m_dark; ///< Holds the dark image
144 :
145 : mx::improc::eigenImage<float> m_ref; ///< Holds the reference image
146 :
147 : bool m_updated{ false }; ///< Indicates that the coordinates were updated was updated
148 :
149 : bool m_skipped{ false }; ///< Indicates that the image failed quality control and this is a skip frame
150 :
151 : float m_x{ 0 }; ///< The current x coordinate
152 : float m_last_x{ 0 }; ///< The previous x coordinate
153 :
154 : float m_y{ 0 }; ///< The current y coordinate
155 : float m_last_y{ 0 }; ///< The previous y coordinate
156 :
157 : float m_dx{ 0 }; ///< The offset in x to apply to non-skipped measurements
158 : float m_dy{ 0 }; ///< The offset in y to apply to non-skipped measurements
159 :
160 : float m_fps{ 0 }; ///< The frame rate from the source camera
161 :
162 : bool m_shutter{ false };
163 :
164 : mx::sigproc::circularBufferIndex<float, cbIndexT> m_pcb; ///< Circular buffer for max pixel (p=peak)
165 : mx::sigproc::circularBufferIndex<float, cbIndexT> m_xcb; ///< Circular buffer for x COL coords
166 : mx::sigproc::circularBufferIndex<float, cbIndexT> m_ycb; ///< Circular buffer for y COL coords
167 :
168 : std::vector<float> m_pcbD; ///< Vector for doing calcs on max pixel
169 : std::vector<float> m_xcbD; ///< Vector for doing calcs on x COL coords
170 : std::vector<float> m_ycbD; ///< Vector for doing calcs on y COL coords
171 :
172 : float m_mnp{ 0 }; ///< The mean max pixel over the stats time
173 : float m_rmsp{ 0 }; ///< The rms max pixel over the stats time
174 :
175 : float m_mnx{ 0 }; ///< The mean x coord over the stats time
176 : float m_rmsx{ 0 }; ///< The rms x coord over the stats time
177 : float m_mny{ 0 }; ///< The mean y coord over the stats time
178 : float m_rmsy{ 0 }; ///< The rms y coord over the stats time
179 :
180 : uint64_t m_skipped_updating{ 0 };
181 : uint64_t m_skipped_updating_last{ 0 };
182 :
183 : uint64_t m_skipped_DeltaFromMax{ 0 };
184 : uint64_t m_skipped_DeltaFromMax_last{ 0 };
185 :
186 : uint64_t m_skipped_MaxRmsUp{ 0 };
187 : uint64_t m_skipped_MaxRmsUp_last{ 0 };
188 :
189 : uint64_t m_skipped_MaxRmsDown{ 0 };
190 : uint64_t m_skipped_MaxRmsDown_last{ 0 };
191 :
192 : uint64_t m_skipped_XRms{ 0 };
193 : uint64_t m_skipped_XRms_last{ 0 };
194 :
195 : uint64_t m_skipped_YRms{ 0 };
196 : uint64_t m_skipped_YRms_last{ 0 };
197 :
198 : public:
199 : /// Default c'tor.
200 : psfFit();
201 :
202 : /// D'tor, declared and defined for noexcept.
203 : ~psfFit() noexcept;
204 :
205 : virtual void setupConfig();
206 :
207 : /// Implementation of loadConfig logic, separated for testing.
208 : /** This is called by loadConfig().
209 : */
210 : int loadConfigImpl(
211 : mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
212 :
213 : virtual void loadConfig();
214 :
215 : /// Startup function
216 : /**
217 : *
218 : */
219 : virtual int appStartup();
220 :
221 : /// Implementation of the FSM for psfFit.
222 : /**
223 : * \returns 0 on no critical error
224 : * \returns -1 on an error requiring shutdown
225 : */
226 : virtual int appLogic();
227 :
228 : /// Shutdown the app.
229 : /**
230 : *
231 : */
232 : virtual int appShutdown();
233 :
234 : // shmimMonitor interface:
235 : int allocate( const dev::shmimT & );
236 :
237 : int processImage( void *curr_src, const dev::shmimT & );
238 :
239 : // shmimMonitor interface for dark:
240 : int allocate( const darkShmimT & );
241 :
242 : int processImage( void *curr_src, const darkShmimT & );
243 :
244 : // shmimMonitor interface for reference:
245 : int allocate( const refShmimT & );
246 :
247 : int processImage( void *curr_src, const refShmimT & );
248 :
249 : protected:
250 : std::mutex m_imageMutex;
251 :
252 : sem_t m_smSemaphore{ 0 }; ///< Semaphore used to synchronize the fg thread and the sm thread.
253 :
254 : public:
255 : /** \name dev::frameGrabber interface
256 : *
257 : * @{
258 : */
259 :
260 : /// Implementation of the framegrabber configureAcquisition interface
261 : /**
262 : * \returns 0 on success
263 : * \returns -1 on error
264 : */
265 : int configureAcquisition();
266 :
267 : /// Implementation of the framegrabber fps interface
268 : /**
269 : * \todo this needs to infer the stream fps and return it
270 : */
271 0 : float fps()
272 : {
273 0 : return m_fps;
274 : }
275 :
276 : /// Implementation of the framegrabber startAcquisition interface
277 : /**
278 : * \returns 0 on success
279 : * \returns -1 on error
280 : */
281 : int startAcquisition();
282 :
283 : /// Implementation of the framegrabber acquireAndCheckValid interface
284 : /**
285 : * \returns 0 on success
286 : * \returns -1 on error
287 : */
288 : int acquireAndCheckValid();
289 :
290 : /// Implementation of the framegrabber loadImageIntoStream interface
291 : /**
292 : * \returns 0 on success
293 : * \returns -1 on error
294 : */
295 : int loadImageIntoStream( void *dest /**< [in] */ );
296 :
297 : /// Implementation of the framegrabber reconfig interface
298 : /**
299 : * \returns 0 on success
300 : * \returns -1 on error
301 : */
302 : int reconfig();
303 :
304 : ///@}
305 :
306 : protected:
307 : /** \name INDI
308 : * @{
309 : */
310 :
311 : pcf::IndiProperty m_indiP_values;
312 :
313 : pcf::IndiProperty m_indiP_reset;
314 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_reset );
315 :
316 : pcf::IndiProperty m_indiP_statsTime;
317 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_statsTime );
318 :
319 : pcf::IndiProperty m_indiP_deltaPixThresh;
320 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_deltaPixThresh );
321 :
322 : pcf::IndiProperty m_indiP_sigmaMaxThreshUp;
323 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_sigmaMaxThreshUp );
324 :
325 : pcf::IndiProperty m_indiP_fractionMaxThreshDown;
326 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_fractionMaxThreshDown );
327 :
328 : pcf::IndiProperty m_indiP_sigmaPixThresh;
329 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_sigmaPixThresh );
330 :
331 : pcf::IndiProperty m_indiP_dx;
332 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_dx );
333 :
334 : pcf::IndiProperty m_indiP_dy;
335 0 : INDI_NEWCALLBACK_DECL( psfFit, m_indiP_dy );
336 :
337 : pcf::IndiProperty m_indiP_fpsSource;
338 0 : INDI_SETCALLBACK_DECL( psfFit, m_indiP_fpsSource );
339 :
340 : pcf::IndiProperty m_indiP_shutter;
341 0 : INDI_SETCALLBACK_DECL( psfFit, m_indiP_shutter );
342 :
343 : ///@}
344 :
345 : /** \name Telemeter Interface
346 : *
347 : * @{
348 : */
349 : int checkRecordTimes();
350 :
351 : int recordTelem( const telem_fgtimings * );
352 :
353 : ///@}
354 : };
355 :
356 : inline psfFit::psfFit() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
357 : {
358 : darkShmimMonitorT::m_getExistingFirst = true;
359 : refShmimMonitorT::m_getExistingFirst = true;
360 :
361 : return;
362 : }
363 :
364 0 : inline psfFit::~psfFit() noexcept
365 : {
366 0 : }
367 :
368 0 : inline void psfFit::setupConfig()
369 : {
370 0 : SHMIMMONITOR_SETUP_CONFIG( config );
371 0 : SHMIMMONITORT_SETUP_CONFIG( darkShmimMonitorT, config );
372 0 : SHMIMMONITORT_SETUP_CONFIG( refShmimMonitorT, config );
373 0 : FRAMEGRABBER_SETUP_CONFIG( config );
374 0 : TELEMETER_SETUP_CONFIG( config );
375 :
376 0 : config.add( "fitter.fpsDevice",
377 : "",
378 : "fitter.fpsDevice",
379 : argType::Required,
380 : "fitter",
381 : "fpsDevice",
382 : false,
383 : "string",
384 : "Device name for getting fps to set circular buffer length." );
385 0 : config.add( "fitter.fpsProperty",
386 : "",
387 : "fitter.fpsProperty",
388 : argType::Required,
389 : "fitter",
390 : "fpsProperty",
391 : false,
392 : "string",
393 : "Property name for getting fps to set circular buffer length. Default is 'fps'." );
394 0 : config.add( "fitter.fpsElement",
395 : "",
396 : "fitter.fpsElement",
397 : argType::Required,
398 : "fitter",
399 : "fpsElement",
400 : false,
401 : "string",
402 : "Property name for getting fps to set circular buffer length. Default is 'current'." );
403 0 : config.add( "fitter.fpsTol",
404 : "",
405 : "fitter.fpsTol",
406 : argType::Required,
407 : "fitter",
408 : "fpsTol",
409 : false,
410 : "float",
411 : "Tolerance for detecting a change in FPS. Default is 0." );
412 0 : config.add( "fitter.defaultFPS",
413 : "",
414 : "fitter.defaultFPS",
415 : argType::Required,
416 : "fitter",
417 : "defaultFPS",
418 : false,
419 : "realT",
420 : "Default FPS at startup, will enable changing average length with psdTime before INDI available." );
421 :
422 0 : config.add( "fitter.shutterDevice",
423 : "",
424 : "fitter.shutterDevice",
425 : argType::Required,
426 : "fitter",
427 : "shutterDevice",
428 : false,
429 : "string",
430 : "Device name for getting shutter state to reset circular buffers" );
431 0 : config.add( "fitter.shutterProperty",
432 : "",
433 : "fitter.shutterProperty",
434 : argType::Required,
435 : "fitter",
436 : "shutterProperty",
437 : false,
438 : "string",
439 : "Property name for getting shutter state to reset circular buffers. Default is 'shutter'." );
440 0 : config.add( "fitter.shutterElement",
441 : "",
442 : "fitter.shutterElement",
443 : argType::Required,
444 : "fitter",
445 : "shutterElement",
446 : false,
447 : "string",
448 : "Property name for getting shutter state to reset circular buffers. Default is 'toggle'." );
449 :
450 0 : config.add( "fitter.deltaPixThresh",
451 : "",
452 : "fitter.deltaPixThresh",
453 : argType::Required,
454 : "fitter",
455 : "deltaPixThresh",
456 : false,
457 : "float",
458 : "Threshold in pixels for skipping frame due to mismatch between max and c.o.l. Default 8." );
459 0 : config.add( "fitter.sigmaMaxThreshUp",
460 : "",
461 : "fitter.sigmaMaxThreshUp",
462 : argType::Required,
463 : "fitter",
464 : "sigmaMaxThreshUp",
465 : false,
466 : "float",
467 : "Threshold in rms for skipping frame due to max positive difference from mean max. Default 5." );
468 0 : config.add( "fitter.fractionMaxThreshDown",
469 : "",
470 : "fitter.fractionMaxThreshDown",
471 : argType::Required,
472 : "fitter",
473 : "fractionMaxThreshDown",
474 : false,
475 : "float",
476 : "Threshold in fraction of the mean max for skipping frame due to drop from mean max. Default 0.1" );
477 :
478 0 : config.add( "fitter.sigmaPixThresh",
479 : "",
480 : "fitter.sigmaPixThresh",
481 : argType::Required,
482 : "fitter",
483 : "sigmaPixThresh",
484 : false,
485 : "float",
486 : "Threshold in rms for skipping frame due to max difference from last value. Example: if this is set "
487 : "to 10, then the pixel postion has to change from -5 sigma to + 5 sigma to be rejected. Default 10." );
488 : }
489 :
490 0 : inline int psfFit::loadConfigImpl( mx::app::appConfigurator &_config )
491 : {
492 0 : SHMIMMONITOR_LOAD_CONFIG( _config );
493 0 : SHMIMMONITORT_LOAD_CONFIG( darkShmimMonitorT, _config );
494 0 : SHMIMMONITORT_LOAD_CONFIG( refShmimMonitorT, _config );
495 :
496 0 : FRAMEGRABBER_LOAD_CONFIG( _config );
497 0 : TELEMETER_LOAD_CONFIG( _config );
498 :
499 0 : _config( m_fpsDevice, "fitter.fpsDevice" );
500 0 : _config( m_fpsProperty, "fitter.fpsProperty" );
501 0 : _config( m_fpsElement, "fitter.fpsElement" );
502 0 : _config( m_fpsTol, "fitter.fpsTol" );
503 0 : _config( m_fps, "fitter.defaultFPS" );
504 :
505 0 : _config( m_shutterDevice, "fitter.shutterDevice" );
506 0 : _config( m_shutterProperty, "fitter.shutterProperty" );
507 0 : _config( m_shutterElement, "fitter.shutterElement" );
508 :
509 0 : _config( m_deltaPixThresh, "fitter.deltaPixThresh" );
510 0 : _config( m_sigmaMaxThreshUp, "fitter.sigmaMaxThreshUp" );
511 0 : _config( m_fractionMaxThreshDown, "fitter.fractionMaxThreshDown" );
512 0 : _config( m_sigmaPixThresh, "fitter.sigmaPixThresh" );
513 :
514 0 : return 0;
515 : }
516 :
517 0 : inline void psfFit::loadConfig()
518 : {
519 0 : loadConfigImpl( config );
520 0 : }
521 :
522 0 : inline int psfFit::appStartup()
523 : {
524 0 : SHMIMMONITOR_APP_STARTUP;
525 0 : SHMIMMONITORT_APP_STARTUP( darkShmimMonitorT );
526 0 : SHMIMMONITORT_APP_STARTUP( refShmimMonitorT );
527 :
528 0 : if( sem_init( &m_smSemaphore, 0, 0 ) < 0 )
529 : {
530 0 : log<software_critical>( { __FILE__, __LINE__, errno, 0, "Initializing S.M. semaphore" } );
531 0 : return -1;
532 : }
533 :
534 0 : FRAMEGRABBER_APP_STARTUP;
535 0 : TELEMETER_APP_STARTUP;
536 :
537 0 : if( m_fpsDevice != "" && m_fpsProperty != "" )
538 : {
539 0 : REG_INDI_SETPROP( m_indiP_fpsSource, m_fpsDevice, m_fpsProperty );
540 : }
541 :
542 0 : if( m_shutterDevice != "" && m_shutterProperty != "" )
543 : {
544 0 : REG_INDI_SETPROP( m_indiP_shutter, m_shutterDevice, m_shutterProperty );
545 : }
546 :
547 0 : CREATE_REG_INDI_RO_NUMBER( m_indiP_values, "values", "", "" );
548 0 : m_indiP_values.add( pcf::IndiElement( "max_mean" ) );
549 0 : m_indiP_values.add( pcf::IndiElement( "max_rms" ) );
550 0 : m_indiP_values.add( pcf::IndiElement( "x_mean" ) );
551 0 : m_indiP_values.add( pcf::IndiElement( "x_rms" ) );
552 0 : m_indiP_values.add( pcf::IndiElement( "y_mean" ) );
553 0 : m_indiP_values.add( pcf::IndiElement( "y_rms" ) );
554 :
555 0 : CREATE_REG_INDI_NEW_REQUESTSWITCH( m_indiP_reset, "reset" );
556 :
557 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_statsTime, "statsTime", 0, 5, 1, "%0.1f", "", "" );
558 0 : m_indiP_statsTime["current"].setValue( m_fitCircBuffMaxTime );
559 0 : m_indiP_statsTime["target"].setValue( m_fitCircBuffMaxTime );
560 :
561 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_deltaPixThresh, "deltaPixThresh", 0, 512, 1, "%0.1f", "", "" );
562 0 : m_indiP_deltaPixThresh["current"].setValue( m_deltaPixThresh );
563 0 : m_indiP_deltaPixThresh["target"].setValue( m_deltaPixThresh );
564 :
565 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaMaxThreshUp, "sigmaMaxThreshUp", 0, 512, 1, "%0.1f", "", "" );
566 0 : m_indiP_sigmaMaxThreshUp["current"].setValue( m_sigmaMaxThreshUp );
567 0 : m_indiP_sigmaMaxThreshUp["target"].setValue( m_sigmaMaxThreshUp );
568 :
569 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_fractionMaxThreshDown, "fractionMaxThreshDown", 0, 512, 1, "%0.1f", "", "" );
570 0 : m_indiP_fractionMaxThreshDown["current"].setValue( m_fractionMaxThreshDown );
571 0 : m_indiP_fractionMaxThreshDown["target"].setValue( m_fractionMaxThreshDown );
572 :
573 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaPixThresh, "sigmaPixThresh", 0, 512, 1, "%0.1f", "", "" );
574 0 : m_indiP_sigmaPixThresh["current"].setValue( m_sigmaPixThresh );
575 0 : m_indiP_sigmaPixThresh["target"].setValue( m_sigmaPixThresh );
576 :
577 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dx, "dx", -100, 100, 1e-2, "%0.02f", "", "" );
578 0 : m_indiP_dx["current"].setValue( m_dx );
579 0 : m_indiP_dx["target"].setValue( m_dx );
580 :
581 0 : CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dy, "dy", -100, 100, 1e-2, "%0.02f", "", "" );
582 0 : m_indiP_dy["current"].setValue( m_dy );
583 0 : m_indiP_dy["target"].setValue( m_dy );
584 :
585 0 : state( stateCodes::OPERATING );
586 :
587 0 : return 0;
588 : }
589 :
590 0 : inline int psfFit::appLogic()
591 : {
592 0 : SHMIMMONITOR_APP_LOGIC;
593 0 : SHMIMMONITORT_APP_LOGIC( darkShmimMonitorT );
594 0 : SHMIMMONITORT_APP_LOGIC( refShmimMonitorT );
595 0 : FRAMEGRABBER_APP_LOGIC;
596 0 : TELEMETER_APP_LOGIC;
597 :
598 0 : if( state() == stateCodes::OPERATING && m_xcb.size() > 0 )
599 : {
600 0 : if( m_xcb.maxEntries() > 2 && m_xcb.size() >= m_xcb.maxEntries() )
601 : {
602 0 : cbIndexT refEntry = m_xcb.earliest();
603 :
604 0 : m_pcbD.resize( m_pcb.maxEntries() - 1 );
605 0 : m_xcbD.resize( m_xcb.maxEntries() - 1 );
606 0 : m_ycbD.resize( m_xcb.maxEntries() - 1 );
607 :
608 0 : for( size_t n = 0; n < m_xcbD.size(); ++n )
609 : {
610 0 : m_pcbD[n] = m_pcb.at( refEntry, n );
611 0 : m_xcbD[n] = m_xcb.at( refEntry, n );
612 0 : m_ycbD[n] = m_ycb.at( refEntry, n );
613 : }
614 :
615 0 : m_mnp = mx::math::vectorMean( m_pcbD );
616 0 : m_rmsp = sqrt( mx::math::vectorVariance( m_pcbD, m_mnp ) );
617 :
618 0 : m_mnx = mx::math::vectorMean( m_xcbD );
619 :
620 0 : m_rmsx = sqrt( mx::math::vectorVariance( m_xcbD, m_mnx ) );
621 :
622 0 : m_mny = mx::math::vectorMean( m_ycbD );
623 0 : m_rmsy = sqrt( mx::math::vectorVariance( m_ycbD, m_mny ) );
624 : }
625 : else
626 : {
627 0 : m_mnp = 0;
628 0 : m_rmsp = 0;
629 :
630 0 : m_mnx = 0;
631 0 : m_rmsx = 0;
632 :
633 0 : m_mny = 0;
634 0 : m_rmsy = 0;
635 : }
636 :
637 0 : int skipped_updating = m_skipped_updating - m_skipped_updating_last;
638 0 : int skipped_DeltaFromMax = m_skipped_DeltaFromMax - m_skipped_DeltaFromMax_last;
639 0 : int skipped_MaxRmsUp = m_skipped_MaxRmsUp - m_skipped_MaxRmsUp_last;
640 0 : int skipped_MaxRmsDown = m_skipped_MaxRmsDown - m_skipped_MaxRmsDown_last;
641 0 : int skipped_XRms = m_skipped_XRms - m_skipped_XRms_last;
642 0 : int skipped_YRms = m_skipped_YRms - m_skipped_YRms_last;
643 :
644 0 : if( skipped_updating || skipped_DeltaFromMax || skipped_MaxRmsUp || skipped_MaxRmsDown || skipped_XRms ||
645 : skipped_YRms )
646 : {
647 0 : std::cerr << "skipping frames: \n";
648 0 : std::cerr << " updating: " << skipped_updating << '\n';
649 0 : std::cerr << " delta-from-max: " << skipped_DeltaFromMax << '\n';
650 0 : std::cerr << " max-rms-up: " << skipped_MaxRmsUp << '\n';
651 0 : std::cerr << " max-rms-down: " << skipped_MaxRmsDown << '\n';
652 0 : std::cerr << " x-rms: " << skipped_XRms << '\n';
653 0 : std::cerr << " y-rms: " << skipped_YRms << '\n';
654 : }
655 0 : m_skipped_updating = m_skipped_updating_last;
656 0 : m_skipped_DeltaFromMax_last = m_skipped_DeltaFromMax;
657 0 : m_skipped_MaxRmsUp_last = m_skipped_MaxRmsUp;
658 0 : m_skipped_MaxRmsDown_last = m_skipped_MaxRmsDown;
659 0 : m_skipped_XRms_last = m_skipped_XRms;
660 0 : m_skipped_YRms_last = m_skipped_YRms;
661 : }
662 : else
663 : {
664 0 : m_mnp = 0;
665 0 : m_rmsp = 0;
666 :
667 0 : m_mnx = 0;
668 0 : m_rmsx = 0;
669 :
670 0 : m_mny = 0;
671 0 : m_rmsy = 0;
672 : }
673 :
674 0 : SHMIMMONITOR_UPDATE_INDI;
675 0 : SHMIMMONITORT_UPDATE_INDI( darkShmimMonitorT );
676 0 : SHMIMMONITORT_UPDATE_INDI( refShmimMonitorT );
677 0 : FRAMEGRABBER_UPDATE_INDI;
678 :
679 0 : updateIfChanged( m_indiP_statsTime, "current", m_fitCircBuffMaxTime );
680 :
681 0 : updatesIfChanged<float>( m_indiP_values,
682 : { "max_mean", "max_rms", "x_mean", "x_rms", "y_mean", "y_rms" },
683 0 : { m_mnp, m_rmsp, m_mnx, m_rmsx, m_mny, m_rmsy } );
684 :
685 0 : updateIfChanged( m_indiP_dx, "current", m_dx );
686 0 : updateIfChanged( m_indiP_dy, "current", m_dy );
687 :
688 :
689 0 : return 0;
690 : }
691 :
692 0 : inline int psfFit::appShutdown()
693 : {
694 0 : SHMIMMONITOR_APP_SHUTDOWN;
695 0 : SHMIMMONITORT_APP_SHUTDOWN( darkShmimMonitorT );
696 0 : SHMIMMONITORT_APP_SHUTDOWN( refShmimMonitorT );
697 0 : FRAMEGRABBER_APP_SHUTDOWN;
698 0 : TELEMETER_APP_SHUTDOWN;
699 :
700 0 : return 0;
701 : }
702 :
703 0 : inline int psfFit::allocate( const dev::shmimT &dummy )
704 : {
705 : static_cast<void>( dummy );
706 :
707 0 : std::lock_guard<std::mutex> guard( m_imageMutex );
708 :
709 0 : m_image.resize( shmimMonitorT::m_width, shmimMonitorT::m_height );
710 0 : m_image.setZero();
711 :
712 0 : if( m_fitCircBuffMaxLength == 0 || m_fitCircBuffMaxTime == 0 || m_fps <= 0 )
713 : {
714 0 : m_pcb.maxEntries( 0 );
715 0 : m_xcb.maxEntries( 0 );
716 0 : m_ycb.maxEntries( 0 );
717 :
718 0 : m_mnp = 0;
719 0 : m_rmsp = 0;
720 :
721 0 : m_mnx = 0;
722 0 : m_rmsx = 0;
723 :
724 0 : m_mny = 0;
725 0 : m_rmsy = 0;
726 : }
727 : else
728 : {
729 : // Set up the fit circ. buffs
730 0 : cbIndexT cbSz = m_fitCircBuffMaxTime * m_fps+1;
731 0 : if( cbSz > m_fitCircBuffMaxLength )
732 : {
733 0 : cbSz = m_fitCircBuffMaxLength;
734 : }
735 0 : if( cbSz < 3 )
736 : {
737 0 : cbSz = 3; // Make variance meaningful
738 : }
739 :
740 0 : std::cerr << "Fit circ. buff size: " << cbSz << ' ' << m_fitCircBuffMaxTime << ' ' << m_fps << '\n';
741 0 : m_pcb.maxEntries( cbSz );
742 0 : m_xcb.maxEntries( cbSz );
743 0 : m_ycb.maxEntries( cbSz );
744 :
745 0 : m_mnp = 0;
746 0 : m_rmsp = 0;
747 :
748 0 : m_mnx = 0;
749 0 : m_rmsx = 0;
750 :
751 0 : m_mny = 0;
752 0 : m_rmsy = 0;
753 : }
754 :
755 0 : m_updated = false;
756 0 : return 0;
757 0 : }
758 :
759 0 : inline int psfFit::processImage( void *curr_src, const dev::shmimT &dummy )
760 : {
761 : static_cast<void>( dummy );
762 :
763 : // counters for managing printing of delta-pix skips when shutter closed
764 : // static int skip_interval = 10;
765 : // static int last_passed = skip_interval + 1;
766 :
767 0 : std::unique_lock<std::mutex> lock( m_imageMutex );
768 :
769 0 : if( m_dark.rows() == m_image.rows() && m_dark.cols() == m_image.cols() )
770 : {
771 0 : if( shmimMonitorT::m_dataType == _DATATYPE_UINT16 )
772 : {
773 0 : for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
774 : {
775 0 : m_image.data()[nn] = ( reinterpret_cast<uint16_t *>( curr_src ) )[nn] - m_dark.data()[nn];
776 : }
777 : }
778 0 : else if( shmimMonitorT::m_dataType == _DATATYPE_FLOAT )
779 : {
780 0 : for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
781 : {
782 0 : m_image.data()[nn] = ( reinterpret_cast<float *>( curr_src ) )[nn] - m_dark.data()[nn];
783 : }
784 : }
785 : }
786 : else
787 : {
788 0 : if( shmimMonitorT::m_dataType == _DATATYPE_UINT16 )
789 : {
790 0 : for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
791 : {
792 0 : m_image.data()[nn] = ( reinterpret_cast<uint16_t *>( curr_src ) )[nn];
793 : }
794 : }
795 0 : else if( shmimMonitorT::m_dataType == _DATATYPE_FLOAT )
796 : {
797 0 : for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
798 : {
799 0 : m_image.data()[nn] = ( reinterpret_cast<float *>( curr_src ) )[nn];
800 : }
801 : }
802 : }
803 :
804 0 : lock.unlock();
805 :
806 : float max;
807 0 : realT local_x = 0;
808 0 : realT local_y = 0;
809 0 : int x = 0;
810 0 : int y = 0;
811 :
812 0 : max = m_image.maxCoeff( &x, &y );
813 :
814 0 : mx::improc::imageCenterOfLight( local_x, local_y, m_image );
815 :
816 0 : bool local_skipped = false;
817 :
818 0 : if( m_shutter )
819 : {
820 0 : local_skipped = true; // silently skip when shutter closed
821 : }
822 :
823 0 : if( !local_skipped && ( fabs( local_x - x ) > m_deltaPixThresh || fabs( local_y - y ) > m_deltaPixThresh ) )
824 : {
825 0 : ++m_skipped_DeltaFromMax;
826 0 : local_skipped = true;
827 :
828 : // We do not add these measurements to stats b/c this means bad PSF
829 : }
830 :
831 : // still filling circular buffer
832 0 : if( !local_skipped && ( m_rmsx == 0 || m_rmsy == 0 || m_rmsp == 0 ) )
833 : {
834 0 : if( m_xcb.maxEntries() > 0 )
835 : {
836 0 : m_pcb.nextEntry( max );
837 0 : m_xcb.nextEntry( local_x );
838 0 : m_ycb.nextEntry( local_y );
839 : }
840 :
841 0 : m_last_x = local_x;
842 0 : m_last_y = local_y;
843 :
844 0 : local_skipped = true;
845 : }
846 :
847 : // The remaining checks are for wild motions but otherwise valid fits (good PSF)
848 :
849 0 : if( !local_skipped && ( ( max - m_mnp ) / m_rmsp > m_sigmaMaxThreshUp ) )
850 : {
851 0 : if( m_pcb.maxEntries() > 0 )
852 : {
853 0 : m_pcb.nextEntry( max );
854 0 : m_xcb.nextEntry( local_x );
855 0 : m_ycb.nextEntry( local_y );
856 : }
857 :
858 0 : m_last_x = local_x;
859 0 : m_last_y = local_y;
860 :
861 0 : ++m_skipped_MaxRmsUp;
862 0 : local_skipped = true;
863 : }
864 :
865 0 : if( !local_skipped && ( ( m_mnp - max ) / m_mnp > ( 1.0 - m_fractionMaxThreshDown ) ) )
866 : {
867 0 : if( m_pcb.maxEntries() > 0 )
868 : {
869 0 : m_pcb.nextEntry( max );
870 0 : m_xcb.nextEntry( local_x );
871 0 : m_ycb.nextEntry( local_y );
872 : }
873 :
874 0 : m_last_x = local_x;
875 0 : m_last_y = local_y;
876 :
877 0 : ++m_skipped_MaxRmsDown;
878 0 : local_skipped = true;
879 : }
880 :
881 0 : if( !local_skipped && ( fabs( local_x - m_last_x ) / m_rmsx > m_sigmaPixThresh ) )
882 : {
883 0 : if( m_xcb.maxEntries() > 0 )
884 : {
885 0 : m_pcb.nextEntry( max );
886 0 : m_xcb.nextEntry( local_x );
887 0 : m_ycb.nextEntry( local_y );
888 : }
889 :
890 0 : m_last_x = local_x;
891 0 : m_last_y = local_y;
892 :
893 0 : ++m_skipped_XRms;
894 0 : local_skipped = true;
895 : }
896 :
897 0 : if( !local_skipped && ( fabs( local_y - m_last_y ) / m_rmsy > m_sigmaPixThresh ) )
898 : {
899 0 : if( m_ycb.maxEntries() > 0 )
900 : {
901 0 : m_pcb.nextEntry( max );
902 0 : m_xcb.nextEntry( local_x );
903 0 : m_ycb.nextEntry( local_y );
904 : }
905 :
906 0 : ++m_skipped_YRms;
907 0 : m_last_x = local_x;
908 0 : m_last_y = local_y;
909 :
910 0 : local_skipped = true;
911 : }
912 :
913 0 : if( local_skipped )
914 : {
915 0 : if( m_ref.rows() == 2 && m_ref.cols() == 1 )
916 : {
917 0 : local_x = m_ref( 0, 0 );
918 0 : local_y = m_ref( 1, 0 );
919 : }
920 : else
921 : {
922 0 : local_x = 0;
923 0 : local_y = 0;
924 : }
925 : }
926 :
927 0 : if( m_updated == true ) // means the framegrabber hasn't posted the last one yet
928 : {
929 0 : ++m_skipped_updating;
930 0 : return 0;
931 : }
932 :
933 0 : m_skipped = local_skipped;
934 0 : m_x = local_x;
935 0 : m_y = local_y;
936 :
937 0 : m_updated = true;
938 :
939 : // signal framegrabber
940 : // Now tell the f.g. to get going
941 0 : if( sem_post( &m_smSemaphore ) < 0 )
942 : {
943 0 : log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to semaphore" } );
944 0 : return -1;
945 : }
946 :
947 0 : if( !m_skipped )
948 : {
949 0 : if( m_xcb.maxEntries() > 0 )
950 : {
951 0 : m_pcb.nextEntry( max );
952 0 : m_xcb.nextEntry( m_x );
953 0 : m_ycb.nextEntry( m_y );
954 : }
955 :
956 0 : m_last_x = m_x;
957 0 : m_last_y = m_y;
958 : }
959 :
960 0 : return 0;
961 0 : }
962 :
963 0 : int psfFit::allocate( const darkShmimT &dummy )
964 : {
965 : static_cast<void>( dummy );
966 :
967 0 : std::lock_guard<std::mutex> guard( m_imageMutex );
968 :
969 0 : if( darkShmimMonitorT::m_dataType != IMAGESTRUCT_FLOAT )
970 : {
971 0 : return log<software_error, -1>( { __FILE__, __LINE__, "dark is not float" } );
972 : }
973 :
974 0 : m_dark.resize( darkShmimMonitorT::m_width, darkShmimMonitorT::m_height );
975 0 : m_dark.setZero();
976 :
977 0 : return 0;
978 0 : }
979 :
980 0 : int psfFit::processImage( void *curr_src, const darkShmimT &dummy )
981 : {
982 : static_cast<void>( dummy );
983 :
984 0 : std::unique_lock<std::mutex> lock( m_imageMutex );
985 :
986 0 : for( unsigned nn = 0; nn < darkShmimMonitorT::m_width * darkShmimMonitorT::m_height; ++nn )
987 : {
988 0 : m_dark.data()[nn] = ( reinterpret_cast<float *>( curr_src ) )[nn];
989 : }
990 :
991 0 : lock.unlock();
992 :
993 0 : log<text_log>( "dark updated", logPrio::LOG_INFO );
994 :
995 0 : return 0;
996 0 : }
997 :
998 0 : int psfFit::allocate( const refShmimT &dummy )
999 : {
1000 : static_cast<void>( dummy );
1001 :
1002 0 : std::lock_guard<std::mutex> guard( m_imageMutex );
1003 :
1004 0 : if( refShmimMonitorT::m_dataType != IMAGESTRUCT_FLOAT )
1005 : {
1006 0 : return log<software_error, -1>( { __FILE__, __LINE__, "ref is not float" } );
1007 : }
1008 :
1009 0 : m_ref.resize( refShmimMonitorT::m_width, refShmimMonitorT::m_height );
1010 0 : m_ref.setZero();
1011 :
1012 0 : return 0;
1013 0 : }
1014 :
1015 0 : int psfFit::processImage( void *curr_src, const refShmimT &dummy )
1016 : {
1017 : static_cast<void>( dummy );
1018 :
1019 0 : std::unique_lock<std::mutex> lock( m_imageMutex );
1020 :
1021 0 : for( unsigned nn = 0; nn < refShmimMonitorT::m_width * refShmimMonitorT::m_height; ++nn )
1022 : {
1023 0 : m_ref.data()[nn] = ( reinterpret_cast<float *>( curr_src ) )[nn];
1024 : }
1025 :
1026 0 : lock.unlock();
1027 :
1028 0 : log<text_log>( "reference updated", logPrio::LOG_INFO );
1029 :
1030 0 : return 0;
1031 0 : }
1032 :
1033 0 : inline int psfFit::configureAcquisition()
1034 : {
1035 :
1036 0 : frameGrabberT::m_width = 2;
1037 0 : frameGrabberT::m_height = 1;
1038 0 : frameGrabberT::m_dataType = _DATATYPE_FLOAT;
1039 :
1040 0 : return 0;
1041 : }
1042 :
1043 0 : inline int psfFit::startAcquisition()
1044 : {
1045 0 : return 0;
1046 : }
1047 :
1048 0 : inline int psfFit::acquireAndCheckValid()
1049 : {
1050 : timespec ts;
1051 :
1052 0 : if( clock_gettime( CLOCK_REALTIME, &ts ) < 0 )
1053 : {
1054 0 : log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
1055 0 : return -1;
1056 : }
1057 :
1058 0 : ts.tv_sec += 1;
1059 :
1060 0 : if( sem_timedwait( &m_smSemaphore, &ts ) == 0 )
1061 : {
1062 0 : if( m_updated )
1063 : {
1064 0 : clock_gettime( CLOCK_REALTIME, &m_currImageTimestamp );
1065 0 : return 0;
1066 : }
1067 : else
1068 : {
1069 0 : return 1;
1070 : }
1071 : }
1072 : else
1073 : {
1074 0 : return 1;
1075 : }
1076 : }
1077 :
1078 0 : inline int psfFit::loadImageIntoStream( void *dest )
1079 : {
1080 0 : if( !m_skipped )
1081 : {
1082 0 : ( reinterpret_cast<float *>( dest ) )[0] = m_x - m_dx;
1083 0 : ( reinterpret_cast<float *>( dest ) )[1] = m_y - m_dy;
1084 : }
1085 : else
1086 : {
1087 0 : ( reinterpret_cast<float *>( dest ) )[0] = m_x;
1088 0 : ( reinterpret_cast<float *>( dest ) )[1] = m_y;
1089 : }
1090 :
1091 0 : m_updated = false;
1092 :
1093 0 : return 0;
1094 : }
1095 :
1096 0 : inline int psfFit::reconfig()
1097 : {
1098 0 : return 0;
1099 : }
1100 :
1101 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_reset )( const pcf::IndiProperty &ipRecv )
1102 : {
1103 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_reset, ipRecv );
1104 :
1105 0 : if( ipRecv.find( "request" ) != true ) // this isn't valid
1106 : {
1107 0 : return -1;
1108 : }
1109 :
1110 0 : if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
1111 : {
1112 0 : log<text_log>( "reset requested", logPrio::LOG_NOTICE );
1113 0 : shmimMonitorT::m_restart = true;
1114 : }
1115 :
1116 0 : return 0;
1117 : }
1118 :
1119 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_statsTime )( const pcf::IndiProperty &ipRecv )
1120 : {
1121 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_statsTime, ipRecv );
1122 :
1123 : float target;
1124 :
1125 0 : if( indiTargetUpdate( m_indiP_statsTime, target, ipRecv, true ) < 0 )
1126 : {
1127 0 : log<software_error>( { __FILE__, __LINE__ } );
1128 0 : return -1;
1129 : }
1130 :
1131 0 : m_fitCircBuffMaxTime = target;
1132 :
1133 0 : shmimMonitorT::m_restart = true;
1134 :
1135 0 : log<text_log>( "set statsTime = " + std::to_string( m_fitCircBuffMaxTime ), logPrio::LOG_NOTICE );
1136 :
1137 0 : return 0;
1138 : }
1139 :
1140 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_deltaPixThresh )( const pcf::IndiProperty &ipRecv )
1141 : {
1142 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_deltaPixThresh, ipRecv );
1143 :
1144 : float target;
1145 :
1146 0 : if( indiTargetUpdate( m_indiP_deltaPixThresh, target, ipRecv, true ) < 0 )
1147 : {
1148 0 : log<software_error>( { __FILE__, __LINE__ } );
1149 0 : return -1;
1150 : }
1151 :
1152 0 : m_deltaPixThresh = target;
1153 0 : updatesIfChanged<float>( m_indiP_deltaPixThresh, { "current", "target" }, { m_deltaPixThresh, m_deltaPixThresh } );
1154 0 : log<text_log>( "set deltaPixThresh = " + std::to_string( m_deltaPixThresh ), logPrio::LOG_NOTICE );
1155 0 : return 0;
1156 : }
1157 :
1158 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaMaxThreshUp )( const pcf::IndiProperty &ipRecv )
1159 : {
1160 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaMaxThreshUp, ipRecv );
1161 :
1162 : float target;
1163 :
1164 0 : if( indiTargetUpdate( m_indiP_sigmaMaxThreshUp, target, ipRecv, true ) < 0 )
1165 : {
1166 0 : log<software_error>( { __FILE__, __LINE__ } );
1167 0 : return -1;
1168 : }
1169 :
1170 0 : m_sigmaMaxThreshUp = target;
1171 0 : updatesIfChanged<float>(
1172 0 : m_indiP_sigmaMaxThreshUp, { "current", "target" }, { m_sigmaMaxThreshUp, m_sigmaMaxThreshUp } );
1173 :
1174 0 : log<text_log>( "set sigmaMaxThreshUp = " + std::to_string( m_sigmaMaxThreshUp ), logPrio::LOG_NOTICE );
1175 0 : return 0;
1176 : }
1177 :
1178 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_fractionMaxThreshDown )( const pcf::IndiProperty &ipRecv )
1179 : {
1180 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fractionMaxThreshDown, ipRecv );
1181 :
1182 : float target;
1183 :
1184 0 : if( indiTargetUpdate( m_indiP_fractionMaxThreshDown, target, ipRecv, true ) < 0 )
1185 : {
1186 0 : log<software_error>( { __FILE__, __LINE__ } );
1187 0 : return -1;
1188 : }
1189 :
1190 0 : m_fractionMaxThreshDown = target;
1191 0 : updatesIfChanged<float>(
1192 0 : m_indiP_fractionMaxThreshDown, { "current", "target" }, { m_fractionMaxThreshDown, m_fractionMaxThreshDown } );
1193 :
1194 0 : log<text_log>( "set fractionMaxThreshDown = " + std::to_string( m_fractionMaxThreshDown ), logPrio::LOG_NOTICE );
1195 0 : return 0;
1196 : }
1197 :
1198 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaPixThresh )( const pcf::IndiProperty &ipRecv )
1199 : {
1200 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaPixThresh, ipRecv );
1201 :
1202 : float target;
1203 :
1204 0 : if( indiTargetUpdate( m_indiP_sigmaPixThresh, target, ipRecv, true ) < 0 )
1205 : {
1206 0 : log<software_error>( { __FILE__, __LINE__ } );
1207 0 : return -1;
1208 : }
1209 :
1210 0 : m_sigmaPixThresh = target;
1211 0 : updatesIfChanged<float>( m_indiP_sigmaPixThresh, { "current", "target" }, { m_sigmaPixThresh, m_sigmaPixThresh } );
1212 :
1213 0 : log<text_log>( "set fractionMaxThreshDown = " + std::to_string( m_sigmaPixThresh ), logPrio::LOG_NOTICE );
1214 0 : return 0;
1215 : }
1216 :
1217 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dx )( const pcf::IndiProperty &ipRecv )
1218 : {
1219 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dx, ipRecv );
1220 :
1221 : float target;
1222 :
1223 0 : if( indiTargetUpdate( m_indiP_dx, target, ipRecv, true ) < 0 )
1224 : {
1225 0 : log<software_error>( { __FILE__, __LINE__ } );
1226 0 : return -1;
1227 : }
1228 :
1229 0 : m_dx = target;
1230 :
1231 0 : log<text_log>( "set dx = " + std::to_string( m_dx ), logPrio::LOG_NOTICE );
1232 0 : return 0;
1233 : }
1234 :
1235 0 : INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dy )( const pcf::IndiProperty &ipRecv )
1236 : {
1237 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dy, ipRecv );
1238 :
1239 : float target;
1240 :
1241 0 : if( indiTargetUpdate( m_indiP_dy, target, ipRecv, true ) < 0 )
1242 : {
1243 0 : log<software_error>( { __FILE__, __LINE__ } );
1244 0 : return -1;
1245 : }
1246 :
1247 0 : m_dy = target;
1248 :
1249 0 : log<text_log>( "set dy = " + std::to_string( m_dy ), logPrio::LOG_NOTICE );
1250 0 : return 0;
1251 : }
1252 :
1253 0 : INDI_SETCALLBACK_DEFN( psfFit, m_indiP_fpsSource )( const pcf::IndiProperty &ipRecv )
1254 : {
1255 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fpsSource, ipRecv );
1256 :
1257 0 : if( ipRecv.find( m_fpsElement ) != true ) // this isn't valid
1258 : {
1259 0 : return 0;
1260 : }
1261 :
1262 0 : std::lock_guard<std::mutex> guard( m_indiMutex );
1263 :
1264 0 : realT fps = ipRecv[m_fpsElement].get<float>();
1265 :
1266 0 : if( fabs( fps - m_fps ) > m_fpsTol )
1267 : {
1268 0 : m_fps = fps;
1269 :
1270 0 : shmimMonitorT::m_restart = true;
1271 0 : frameGrabberT::m_reconfig = true;
1272 : }
1273 :
1274 0 : return 0;
1275 0 : }
1276 :
1277 0 : INDI_SETCALLBACK_DEFN( psfFit, m_indiP_shutter )( const pcf::IndiProperty &ipRecv )
1278 : {
1279 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_shutter, ipRecv );
1280 :
1281 0 : if( ipRecv.find( m_shutterElement ) != true ) // this isn't valid
1282 : {
1283 0 : return 0;
1284 : }
1285 :
1286 0 : std::lock_guard<std::mutex> guard( m_indiMutex );
1287 :
1288 : bool shutter;
1289 0 : if( ipRecv[m_shutterElement].getSwitchState() == pcf::IndiElement::On )
1290 : {
1291 0 : shutter = true;
1292 : }
1293 : else
1294 : {
1295 0 : shutter = false;
1296 : }
1297 :
1298 0 : if( shutter != m_shutter )
1299 : {
1300 0 : m_shutter = shutter;
1301 :
1302 0 : shmimMonitorT::m_restart = true;
1303 : }
1304 :
1305 0 : return 0;
1306 0 : }
1307 :
1308 0 : inline int psfFit::checkRecordTimes()
1309 : {
1310 0 : return telemeterT::checkRecordTimes( telem_fgtimings() );
1311 : }
1312 :
1313 0 : inline int psfFit::recordTelem( const telem_fgtimings * )
1314 : {
1315 0 : return recordFGTimings( true );
1316 : }
1317 :
1318 : } // namespace app
1319 : } // namespace MagAOX
1320 :
1321 : #endif // psfFit_hpp
|