API
 
Loading...
Searching...
No Matches
userGainCtrl.hpp
Go to the documentation of this file.
1/** \file userGainCtrl.hpp
2 * \brief The MagAO-X user gain control app
3 *
4 * \ingroup app_files
5 */
6
7#ifndef userGainCtrl_hpp
8#define userGainCtrl_hpp
9
10#include <limits>
11
12#include <mx/improc/eigenCube.hpp>
13#include <mx/improc/eigenImage.hpp>
14#include <mx/ioutils/fits/fitsFile.hpp>
15
16#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
17#include "../../magaox_git_version.h"
18
19namespace MagAOX
20{
21namespace app
22{
23
24uint16_t modesAtBlock( uint16_t b )
25{
26 int16_t N = 2* (2*b+1 + 1);
27
28 return (N+1)*(N+1) - 1;
29}
30
31/// Calculate the number of modes in 1 block
32/** A block is 2 Fourier mode indices wide. At index m, there are 2m linear degrees of freedom.
33 * This gives [(2m+1)(2m+1)-1] total Fourier modes. By considering the difference for 2m and 2(m-1) we
34 * find the number of modes in one index is 16m + 8. Note that m here starts from 1.
35 *
36 * Block number b starts from 0, and is related to m by m = 2b + 1
37 */
38uint16_t modesInBlock( uint16_t b /**< [in] the block number */)
39{
40 return 32*b + 24;
41}
42
43/// Calculate the number of blocks and the number of modes per block
44/** A block is 2 Fourier mode m-indices wide, going around to the m < 0 side. At index m, there are 2m linear degrees of freedom.
45 * Block number b starts from 0, and is related to m by m = 2b + 1. So for b+1 blocks, there are N = 2* (2*b+1 + 1) linear
46 * degrees of freedom, giving (N+1)*(N+1) - 1 total Fourier modes, with 32*b + 24 modes per block b.
47 *
48 * Complicating this is the usual practice of putting pure Zernike modes into the beginning of the basis. This accounts for
49 * this if desired, always splitting Tip/Tilt and Focus into separate blocks. Tip/Tilt can optionally be 2 separate blocks.
50 */
51int blockModes( std::vector<uint16_t> & blocks, ///< [out] the block structure. The size is the number of blocks, and each entry contains the nubmer of modes in that block
52 std::vector<std::string> & names, ///< [out] the name of each block
53 uint16_t Nmodes, ///< [in] the total number of modes
54 uint16_t Nzern, ///< [in] the number of Zernikes appended at the front
55 bool splitTT ///< [in] whether or not to split tip and tilt
56 )
57{
58 double Nblocksd = (sqrt(1.0+Nmodes) - 1)/4.;
59 int Nblocks = Nblocksd;
60
61 if(Nblocks < Nblocksd)
62 {
63 ++Nblocks;
64 }
65
66 blocks.clear();
67 names.clear();
68
69 uint16_t tot = 0;
70 if(Nzern > 0)
71 {
72 if(Nzern < 2) //not enough modes for this
73 {
74 //This is dumb, whomever is doing this, you should know.
75 Nblocks += 1;
76 blocks.push_back(1);
77 names.push_back("Tip");
78 tot = 1;
79 }
80 else if(splitTT)
81 {
82 Nblocks += 2;
83 blocks.push_back(1);
84 names.push_back("Tip");
85 blocks.push_back(1);
86 names.push_back("Tilt");
87 tot = 2;
88 }
89 else
90 {
91 Nblocks += 1;
92 blocks.push_back(2);
93 names.push_back("Tip/Tilt");
94 tot = 2;
95 }
96
97 if(Nzern > 2)
98 {
99 //Focus
100 Nblocks += 1;
101 blocks.push_back(1);
102 names.push_back("Focus");
103 ++tot;
104
105 if(Nzern > 3)
106 {
107 Nblocks += 1;
108 blocks.push_back(Nzern - 3);
109 names.push_back("Z " + std::to_string(4)+"-" + std::to_string(Nzern));
110 tot += blocks.back();
111 }
112 }
113 }
114
115 if(tot >= Nmodes) //Here we handle the case of Nzern >= Nmodes.
116 {
117 uint16_t sum = 0;
118 for(size_t n=0; n < blocks.size(); ++n)
119 {
120 sum += blocks[n];
121 }
122
123 if(sum != Nmodes && sum != Nzern)
124 {
125 return -4;
126 }
127
128 return 0;
129 }
130
131 uint16_t currb = 0;
132
133 while(currb < Nblocks)
134 {
135 uint16_t NAtThis = modesAtBlock(currb);
136
137 if(NAtThis <= tot) //Still in the Zernikes at the beginning
138 {
139 //--Nblocks;
140 ++currb;
141 continue;
142 }
143
144 uint16_t Nthis = NAtThis - tot;
145
146 if(tot + Nthis > Nmodes)
147 {
148 Nthis = Nmodes - tot;
149 }
150
151 if(Nthis == 0)
152 {
153 break;
154 }
155
156 blocks.push_back(Nthis);
157 names.push_back("Block " + std::to_string(blocks.size()-1));
158 tot += Nthis;
159 ++currb;
160 }
161
162 uint16_t sum = 0;
163 for(size_t n=0; n < blocks.size(); ++n)
164 {
165 sum += blocks[n];
166 }
167
168 if(sum != Nmodes)
169 {
170 return -3;
171 }
172
173 return 0;
174
175}
176
178{
179 static std::string configSection()
180 {
181 return "gainShmim";
182 };
183
184 static std::string indiPrefix()
185 {
186 return "gainShmim";
187 };
188};
189
191{
192 static std::string configSection()
193 {
194 return "multcoeffShmim";
195 };
196
197 static std::string indiPrefix()
198 {
199 return "multcoeffShmim";
200 };
201};
202
204{
205 static std::string configSection()
206 {
207 return "limitShmim";
208 };
209
210 static std::string indiPrefix()
211 {
212 return "limitShmim";
213 };
214};
215
216/** \defgroup userGainCtrl User Interface to Cacao Gains
217 * \brief Tracks the cacao gain factor vector and updates upon request, using blocks.
218 *
219 * <a href="../handbook/operating/software/apps/userGainCtrl.html">Application Documentation</a>
220 *
221 * \ingroup apps
222 *
223 */
224
225/** \defgroup userGainCtrl_files User Gain Control
226 * \ingroup userGainCtrl
227 */
228
229/** MagAO-X application to provide a user interface to cacao gains
230 *
231 * \ingroup userGainCtrl
232 *
233 */
234class userGainCtrl : public MagAOXApp<true>, public dev::shmimMonitor<userGainCtrl,gainShmimT>,
235 public dev::shmimMonitor<userGainCtrl,multcoeffShmimT>, public dev::shmimMonitor<userGainCtrl,limitShmimT>,
236 public dev::telemeter<userGainCtrl>
237{
238
239 //Give the test harness access.
240 friend class userGainCtrl_test;
241
245
247
248 friend class dev::telemeter<userGainCtrl>;
249
250public:
251
252 //The base shmimMonitor type
256
257 ///Floating point type in which to do all calculations.
258 typedef float realT;
259
260protected:
261
262 /** \name Configurable Parameters
263 *@{
264 */
265 int m_loopNumber {-1};
266 int m_nZern {0};
267 bool m_splitTT {false};
268
269 bool m_individualModes {false};
270
271 ///@}
272
273 mx::improc::eigenImage<realT> m_gainsCurrent; ///< The current gains.
274 mx::improc::eigenImage<realT> m_gainsTarget; ///< The target gains.
275
276 realT (*pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
277
278 mx::improc::eigenImage<realT> m_mcsCurrent; ///< The current gains.
279 mx::improc::eigenImage<realT> m_mcsTarget; ///< The target gains.
280
281 realT (*mc_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
282
283 mx::improc::eigenImage<realT> m_limitsCurrent; ///< The current gains.
284 mx::improc::eigenImage<realT> m_limitsTarget; ///< The target gains.
285
286 realT (*limit_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
287
288 std::vector<uint16_t> m_modeBlockStart;
289 std::vector<uint16_t> m_modeBlockN;
290 std::vector<std::string> m_modeBlockNames;
291
292 int m_totalNModes {0}; ///< The total number of WFS modes in the calib.
293
294 std::vector<float> m_modeBlockGains;
295 std::vector<uint8_t> m_modeBlockGainsConstant;
296
297 std::vector<float> m_modeBlockMCs;
298 std::vector<uint8_t> m_modeBlockMCsConstant;
299
300 std::vector<float> m_modeBlockLims;
301 std::vector<uint8_t> m_modeBlockLimsConstant;
302
304
305 mx::fits::fitsFile<float> m_ff;
306
308
310 float m_powerLawFloor {0.05};
311
312public:
313 /// Default c'tor.
314 userGainCtrl();
315
316 /// D'tor, declared and defined for noexcept.
319
320 virtual void setupConfig();
321
322 /// Implementation of loadConfig logic, separated for testing.
323 /** This is called by loadConfig().
324 */
325 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
326
327 virtual void loadConfig();
328
329 /// Startup function
330 /**
331 *
332 */
333 virtual int appStartup();
334
335 /// Implementation of the FSM for userGainCtrl.
336 /**
337 * \returns 0 on no critical error
338 * \returns -1 on an error requiring shutdown
339 */
340 virtual int appLogic();
341
342 /// Shutdown the app.
343 /**
344 *
345 */
346 virtual int appShutdown();
347
348protected:
349
350 //int checkAOCalib(); ///< Test if the AO calib is accessible.
351
352 //int getAOCalib();
353
354 int getModeBlocks();
355
356 int allocate( const gainShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
357
358 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
359 const gainShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
360 );
361
362 int writeGains();
363
364 int setBlockGain( int n,
365 float g
366 );
367
368 int allocate( const multcoeffShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
369
370 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
371 const multcoeffShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
372 );
373
374 int writeMCs();
375
376 int setBlockMC( int n,
377 float mc
378 );
379
380 int allocate( const limitShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
381
382 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
383 const limitShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
384 );
385
386 int writeLimits();
387
388 int setBlockLimit( int n,
389 float l
390 );
391
392 int setSingleModeNo (int m);
393
394 int setSingleGain( float g );
395
396 int setSingleMC( float mc );
397
398 void updateSingles();
399
400 void powerLawIndex( float pli );
401
402 void powerLawFloor( float plf );
403
404 void powerLawSet();
405
406 pcf::IndiProperty m_indiP_modes;
407
408 pcf::IndiProperty m_indiP_zeroAll;
409
410 std::vector<pcf::IndiProperty> m_indiP_blockGains;
411 std::vector<pcf::IndiProperty> m_indiP_blockMCs;
412 std::vector<pcf::IndiProperty> m_indiP_blockLimits;
413
414 pcf::IndiProperty m_indiP_singleModeNo;
415 pcf::IndiProperty m_indiP_singleGain;
416 pcf::IndiProperty m_indiP_singleMC;
417
418 pcf::IndiProperty m_indiP_powerLawIndex;
419 pcf::IndiProperty m_indiP_powerLawFloor;
420 pcf::IndiProperty m_indiP_powerLawSet;
421
422public:
423
425
427
429
431
435
436 /// The static callback function to be registered for block gains
437 /** Dispatches to the relevant handler
438 *
439 * \returns 0 on success.
440 * \returns -1 on error.
441 */
442 static int st_newCallBack_blockGains( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
443 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
444 );
445
446 /// Callback to process a NEW block gain request
447 /**
448 * \returns 0 on success.
449 * \returns -1 on error.
450 */
451 int newCallBack_blockGains( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
452
453 /// The static callback function to be registered for block mult. coeff.s
454 /** Dispatches to the relevant handler
455 *
456 * \returns 0 on success.
457 * \returns -1 on error.
458 */
459 static int st_newCallBack_blockMCs( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
460 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
461 );
462
463 /// Callback to process a NEW block mult. coeff.s
464 /**
465 * \returns 0 on success.
466 * \returns -1 on error.
467 */
468 int newCallBack_blockMCs( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
469
470 /// The static callback function to be registered for block limits
471 /** Dispatches to the relevant handler
472 *
473 * \returns 0 on success.
474 * \returns -1 on error.
475 */
476 static int st_newCallBack_blockLimits( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
477 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
478 );
479
480 /// Callback to process a NEW block limits
481 /**
482 * \returns 0 on success.
483 * \returns -1 on error.
484 */
485 int newCallBack_blockLimits( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
486
487 /** \name Telemeter Interface
488 *
489 * @{
490 */
491 int checkRecordTimes();
492
493 int recordTelem( const telem_blockgains * );
494
495 int recordBlockGains( bool force = false );
496
497 ///@}
498};
499
500inline
501userGainCtrl::userGainCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
502{
503
507
508 return;
509}
510
511inline
513{
517
518 config.add("loop.number", "", "loop.number", argType::Required, "loop", "number", false, "int", "The loop number");
519 config.add("blocks.splitTT", "", "blocks.splitTT", argType::Required, "blocks", "splitTT", false, "bool", "If true, the first block is split into two modes.");
520 config.add("blocks.nZern", "", "blocks.nZern", argType::Required, "blocks", "nZern", false, "int", "Number of Zernikes at beginning. T/T and F are split, the rest in their own block.");
521
522 config.add("blocks.individualModes", "", "blocks.individualModes", argType::Required, "blocks", "individualModes", false, "bool", "make each block a single mode");
523
525}
526
527inline
528int userGainCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
529{
530 _config(m_loopNumber, "loop.number");
531 _config(m_splitTT, "blocks.splitTT");
532 _config(m_nZern, "blocks.nZern");
533 _config(m_individualModes, "block.individualModes");
534
535 shmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mgainfact";
537
538 mcShmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mmultfact";
540
541 limitShmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mlimitfact";
543
545 {
546 log<text_log>("Error during telemeter config", logPrio::LOG_CRITICAL);
547 m_shutdown = true;
548 }
549
550 return 0;
551}
552
553inline
555{
556 loadConfigImpl(config);
557}
558
559inline
561{
562 createROIndiNumber( m_indiP_modes, "modes", "Loop Modes", "Loop Controls");
563 indi::addNumberElement(m_indiP_modes, "total", 0, 1, 25000, "Total Modes");
564 indi::addNumberElement(m_indiP_modes, "blocks", 0, 1, 99, "Mode Blocks");
566
567
570 {
572 return -1;
573 }
574
575 createStandardIndiNumber<int>( m_indiP_singleModeNo, "singleModeNo", 0, 2400 ,0, "%0d", "");
576 m_indiP_singleModeNo["current"].set(m_singleModeNo);
579
580 createStandardIndiNumber<int>( m_indiP_singleGain, "singleGain", 0, 1.5 ,0, "%0.2f", "");
581 m_indiP_singleGain["current"].set(1);
582 m_indiP_singleGain["target"].set(1);
584
585 createStandardIndiNumber<int>( m_indiP_singleMC, "singleMC", 0, 1.0 ,0, "%0.2f", "");
586 m_indiP_singleMC["current"].set(1);
587 m_indiP_singleMC["target"].set(1);
589
590 createStandardIndiNumber<int>( m_indiP_powerLawIndex, "pwrlaw_index", 0, 10.0 ,0, "%0.2f", "");
594
595 createStandardIndiNumber<int>( m_indiP_powerLawFloor, "pwrlaw_floor", 0, 1.0 ,0, "%0.2f", "");
599
602 {
604 return -1;
605 }
606
608 {
609 return log<software_error,-1>({__FILE__, __LINE__});
610 }
611
613 {
614 return log<software_error,-1>({__FILE__, __LINE__});
615 }
616
618 {
619 return log<software_error,-1>({__FILE__, __LINE__});
620 }
621
622 if(telemeterT::appStartup() < 0)
623 {
624 return log<software_error,-1>({__FILE__,__LINE__});
625 }
626
628
629 return 0;
630}
631
632inline
634{
635 if( shmimMonitorT::appLogic() < 0)
636 {
637 return log<software_error,-1>({__FILE__,__LINE__});
638 }
639
641 {
642 return log<software_error,-1>({__FILE__,__LINE__});
643 }
644
646 {
647 return log<software_error,-1>({__FILE__,__LINE__});
648 }
649
652 {
655 if(state() == stateCodes::READY) state(stateCodes::OPERATING); //we just progress all the way through to operating so shmimMonitor will go.
656 }
657
659 {
660 if(telemeterT::appLogic() < 0)
661 {
663 return 0;
664 }
665 }
666
667 std::unique_lock<std::mutex> lock(m_indiMutex);
668
670 {
672 }
673
675 {
677 }
678
680 {
682 }
683
684 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
685 {
687 }
688
689 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
690 {
692 }
693
694 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
695 {
697 }
698
700
701 return 0;
702}
703
704inline
715
716
717inline
719{
721 {
723
725
726 for(size_t n = 0; n < m_modeBlockNames.size(); ++n)
727 {
728 m_modeBlockNames.push_back("Block " + std::to_string(n));
729 }
730 }
731 else
732 {
734 }
735
736 uint16_t Nb = m_modeBlockN.size();
737
738 m_modeBlockStart.resize(m_modeBlockN.size());
739 m_modeBlockStart[0] = 0;
740 for(size_t n = 1; n < m_modeBlockN.size(); ++n)
741 {
743 }
744
745 log<text_log>("loading new gain block structure");
746
747 m_modeBlockGains.resize(Nb);
749
750 m_modeBlockMCs.resize(Nb);
752
753 m_modeBlockLims.resize(Nb);
755
756 //-- modify INDI vars --
757 std::unique_lock<std::mutex> indilock(m_indiMutex);
758
760 m_indiP_modes["blocks"] = m_modeBlockStart.size();
761
762 //First just delete all existing blockXX elements
763 for(int n=0; n < 100; ++n)
764 {
765 char str[16];
766 snprintf(str, sizeof(str), "%02d", n);
767 std::string en = "block";
768 en += str;
769
770 if(m_indiP_modes.find(en)) m_indiP_modes.remove(en);
771 }
772
773 //Erase existing block gains
774 if(m_indiP_blockGains.size() > 0)
775 {
776 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
777 {
778 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockGains[n]);
779 if(!m_indiNewCallBacks.erase(m_indiP_blockGains[n].createUniqueKey()))
780 {
781 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockGains[n].createUniqueKey()});
782 }
783 }
784 }
785 m_indiP_blockGains.clear();
786
787 //Erase existing block mult. coeffs
788 if(m_indiP_blockMCs.size() > 0)
789 {
790 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
791 {
792 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockMCs[n]);
793 if(!m_indiNewCallBacks.erase(m_indiP_blockMCs[n].createUniqueKey()))
794 {
795 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockMCs[n].createUniqueKey()});
796 }
797 }
798 }
799 m_indiP_blockMCs.clear();
800
801 //Erase existing block limits
802 if(m_indiP_blockLimits.size() > 0)
803 {
804 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
805 {
806 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockLimits[n]);
807 if(!m_indiNewCallBacks.erase(m_indiP_blockLimits[n].createUniqueKey()))
808 {
809 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockLimits[n].createUniqueKey()});
810 }
811 }
812 }
813 m_indiP_blockLimits.clear();
814
815 m_indiP_blockGains.resize(Nb);
816 m_indiP_blockMCs.resize(Nb);
817 m_indiP_blockLimits.resize(Nb);
818
819 //Then add in what we want.
820 for(size_t n=0; n < Nb; ++n)
821 {
822 char str[16];
823 int nn = n;
824 snprintf(str, sizeof(str), "%02d", nn);
825 std::string en = "block";
826 en += str;
827 indi::addNumberElement(m_indiP_modes, en, 0, 1, 99, "Block " + std::to_string(nn));
829
830 createStandardIndiNumber<float>( m_indiP_blockGains[n], en + "_gain", 0.0, 10.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Gain", "Loop Controls");
832 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockGains[n]);
833
834 createStandardIndiNumber<float>( m_indiP_blockMCs[n], en + "_multcoeff", 0.0, 1.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Mult. Coeff", "Loop Controls");
836 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockMCs[n]);
837
838 createStandardIndiNumber<float>( m_indiP_blockLimits[n], en + "_limit", 0.0, 100.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Limit", "Loop Controls");
840 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockLimits[n]);
841 }
842
843 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_modes); //might not exist yet!
844
845 return 0;
846}
847
848inline
850{
851 static_cast<void>(dummy); //be unused
852
853 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
854
857
859
861
862 return 0;
863}
864
865inline
866int userGainCtrl::processImage( void * curr_src,
867 const gainShmimT & dummy
868 )
869{
870 static_cast<void>(dummy); //be unused
871
873
874 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
875
876 realT * data = m_gainsCurrent.data();
877
879 {
880 data[nn] = pixget(curr_src, nn);
881 }
882
883 //update blocks here.
884
885 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
886 {
887 double mng = 0;
888
889 int NN = 0;
890
891 for(int m =0; m < m_modeBlockN[n]; ++m)
892 {
893 if(m_modeBlockStart[n] + m >= m_gainsCurrent.rows()) break;
895 ++NN;
896 }
897
899
900 bool constant = true;
901
902 for(int m =0; m < m_modeBlockN[n]; ++m)
903 {
904 if(m_modeBlockStart[n] + m >= m_gainsCurrent.rows()) break;
906 {
907 constant = false;
908 break;
909 }
910 }
911
912 m_modeBlockGainsConstant[n] = constant;
913
914 }
915
916 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
917 {
919 }
920
921 lock.unlock();
922
924
925 return 0;
926}
927
928inline
930{
932 char * dest = static_cast<char *>(shmimMonitorT::m_imageStream.array.raw);
933
935
936 //Set the time of last write
938
939 //Set the image acquisition timestamp
941
942 //Update cnt0
944
945 //And post
948
949 return 0;
950}
951
953 float g
954 )
955{
956 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
957
959
960 //Apply a delta to each mode in the block
961 //to preserve intra-block differences, unless g is 0
962 if(g > 0)
963 {
964 for(int m =0; m < m_modeBlockN[n]; ++m)
965 {
966 if(m_modeBlockStart[n] + m > m_gainsTarget.rows() -1) break;
968 if(newg < 0) newg = 0;
970 }
971 }
972 else
973 {
974 for(int m =0; m < m_modeBlockN[n]; ++m)
975 {
976 if(m_modeBlockStart[n] + m > m_gainsTarget.rows() -1) break;
977
979 }
980 }
981 //lock.unlock();
982 recordBlockGains(true);
983 writeGains();
984 return 0;
985}
986
987inline
989{
990 static_cast<void>(dummy); //be unused
991
992 int n = 0;
993
995 {
996 mx::sys::milliSleep(100);
997 ++n;
998 }
999
1001 {
1002 return -1;
1003 }
1004
1005 std::unique_lock<std::mutex> lock(m_indiMutex);
1006
1009
1011
1012 return 0;
1013}
1014
1015inline
1016int userGainCtrl::processImage( void * curr_src,
1017 const multcoeffShmimT & dummy
1018 )
1019{
1020 static_cast<void>(dummy); //be unused
1021
1023
1024 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1025
1026 realT * data = m_mcsCurrent.data();
1027
1029 {
1030 data[nn] = mc_pixget(curr_src, nn);
1031 }
1032
1033 //update blocks here.
1034
1035 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
1036 {
1037 double mng = 0;
1038
1039 int NN = 0;
1040 for(int m =0; m < m_modeBlockN[n]; ++m)
1041 {
1042 if(m_modeBlockStart[n] + m >= m_mcsCurrent.rows()) break;
1044 ++NN;
1045 }
1046
1047 m_modeBlockMCs[n] = mng / NN;
1048
1049
1050 bool constant = true;
1051
1052 for(int m =0; m < m_modeBlockN[n]; ++m)
1053 {
1054 if(m_modeBlockStart[n] + m >= m_mcsCurrent.rows()) break;
1056 {
1057 constant = false;
1058 break;
1059 }
1060 }
1061
1062 m_modeBlockMCsConstant[n] = constant;
1063 }
1064
1065 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
1066 {
1068 }
1069
1070 lock.unlock();
1071
1073
1074 return 0;
1075}
1076
1077inline
1079{
1081 char * dest = static_cast<char *>(mcShmimMonitorT::m_imageStream.array.raw);
1082
1084
1085 //Set the time of last write
1087
1088 //Set the image acquisition timestamp
1090
1091 //Update cnt0
1093
1094 //And post
1097
1098 return 0;
1099}
1100
1102 float mc
1103 )
1104{
1105 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1106
1108
1109 //Apply a delta to each mode in the block
1110 //to preserve intra-block differences
1111 for(int m =0; m < m_modeBlockN[n]; ++m)
1112 {
1113 if(m_modeBlockStart[n] + m > m_mcsTarget.rows() -1) break;
1115 }
1116 lock.unlock();
1117 recordBlockGains(true);
1118 writeMCs();
1119 return 0;
1120}
1121
1122inline
1124{
1125 static_cast<void>(dummy); //be unused
1126
1127 int n = 0;
1128
1130 {
1131 mx::sys::milliSleep(100);
1132 ++n;
1133 }
1134
1136 {
1137 return -1;
1138 }
1139
1140 std::unique_lock<std::mutex> lock(m_indiMutex);
1141
1144
1146
1147 return 0;
1148}
1149
1150inline
1151int userGainCtrl::processImage( void * curr_src,
1152 const limitShmimT & dummy
1153 )
1154{
1155 static_cast<void>(dummy); //be unused
1156
1158
1159 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1160
1161 realT * data = m_limitsCurrent.data();
1162
1164 {
1165 data[nn] = limit_pixget(curr_src, nn);
1166 }
1167
1168 //update blocks here.
1169
1170 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
1171 {
1172 double mng = 0;
1173
1174 int NN = 0;
1175 for(int m =0; m < m_modeBlockN[n]; ++m)
1176 {
1177 if(m_modeBlockStart[n] + m >= m_limitsCurrent.rows()) break;
1179 ++NN;
1180 }
1181
1182 m_modeBlockLims[n] = mng / NN;
1183
1184 bool constant = true;
1185
1186 for(int m =0; m < m_modeBlockN[n]; ++m)
1187 {
1188 if(m_modeBlockStart[n] + m >= m_limitsCurrent.rows()) break;
1190 {
1191 constant = false;
1192 break;
1193 }
1194 }
1195
1196 m_modeBlockLimsConstant[n] = constant;
1197 }
1198
1199 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
1200 {
1202 }
1203
1204 lock.unlock();
1205
1207
1208 return 0;
1209}
1210
1211inline
1213{
1215 char * dest = static_cast<char *>(limitShmimMonitorT::m_imageStream.array.raw);// + next_cnt1*m_width*m_height*m_typeSize;
1216
1218
1219 //Set the time of last write
1221
1222 //Set the image acquisition timestamp
1224
1225 //Update cnt0
1227
1228 //And post
1231
1232 return 0;
1233}
1234
1236 float l
1237 )
1238{
1239 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1240
1242
1243 //Apply a delta to each mode in the block
1244 //to preserve intra-block differences
1245 for(int m =0; m < m_modeBlockN[n]; ++m)
1246 {
1247 if(m_modeBlockStart[n] + m > m_limitsTarget.rows() -1) break;
1249 }
1250 lock.unlock();
1251 recordBlockGains(true);
1252 writeLimits();
1253
1254 return 0;
1255}
1256
1258{
1259 m_singleModeNo = m;
1260
1262
1264 float g = m_gainsCurrent (m_singleModeNo,0);
1265
1266 updateIfChanged(m_indiP_singleGain, std::vector<std::string>({"current", "target"}), std::vector<float>({g,g}));
1267
1269 float mc = m_mcsCurrent(m_singleModeNo,0);
1270
1271 updateIfChanged(m_indiP_singleMC, std::vector<std::string>({"current", "target"}), std::vector<float>({mc,mc}));
1272
1273 return 0;
1274}
1275
1277{
1280 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1282 lock.unlock();
1283 recordBlockGains(true);
1284 writeGains();
1285 return 0;
1286}
1287
1289{
1292 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1294 lock.unlock();
1295 recordBlockGains(true);
1296 writeMCs();
1297 return 0;
1298}
1299
1301{
1303 float g = m_gainsCurrent (m_singleModeNo,0);
1304
1305 updateIfChanged(m_indiP_singleGain, std::vector<std::string>({"current", "target"}), std::vector<float>({g,g}));
1306
1308 float mc = m_mcsCurrent(m_singleModeNo,0);
1309
1310 updateIfChanged(m_indiP_singleMC, std::vector<std::string>({"current", "target"}), std::vector<float>({mc,mc}));
1311
1312}
1313
1315{
1316 if(pli < 0)
1317 {
1318 pli = 0;
1319 }
1320
1322 updateIfChanged(m_indiP_powerLawIndex, std::vector<std::string>({"current", "target"}), std::vector<float>({pli,pli}));
1323}
1324
1326{
1328
1329 updateIfChanged(m_indiP_powerLawFloor, std::vector<std::string>({"current", "target"}), std::vector<float>({plf,plf}));
1330}
1331
1333{
1334 uint16_t block0 = 0;
1335
1336 if(m_nZern > 0)
1337 {
1338 if(m_nZern > 1)
1339 {
1340 if(m_splitTT)
1341 {
1342 block0 = 2;
1343 }
1344 else
1345 {
1346 block0 = 1;
1347 }
1348 }
1349
1350 if(m_nZern > 2)
1351 {
1352 ++block0;
1353 }
1354
1355 if(m_nZern > 3)
1356 {
1357 ++block0;
1358 }
1359 //Now have accounted for T/T and focus.
1360
1361 uint16_t currb = 1;
1362 while(modesAtBlock(currb) < m_nZern)
1363 {
1364 ++currb;
1365 ++block0;
1366 }
1367 }
1368
1369 if(block0 >= m_modeBlockStart.size())
1370 {
1371 return;
1372 }
1373
1374 if(m_powerLawIndex < 0)
1375 {
1376 m_powerLawIndex = 0;
1377 }
1378
1380 float gain0 = m_modeBlockGains[block0];
1381 for(size_t n=block0+1; n < m_modeBlockStart.size(); ++n)
1382 {
1383 float mode = m_modeBlockStart[n] + 0.5*m_modeBlockN[n];
1384
1385 float imd1=(mode-mode0)/(m_totalNModes-mode0);
1386 float imd2=pow(1.0-imd1, -m_powerLawIndex) * gain0;
1387 float gain=(1-m_powerLawFloor)*imd2+m_powerLawFloor;
1388
1389 if(gain < 0) gain = 0;
1390
1391 setBlockGain(n, gain);
1392
1393 //Now wait on the update, otherwise the next command can overwrite from m_gainsCurrent
1394 int nt = 0;
1395 while(fabs(m_modeBlockGains[n] - gain) > 1e-5 && nt < 100)
1396 {
1397 mx::sys::milliSleep(5);
1398 ++nt;
1399 }
1400 }
1401
1402 log<text_log>("Set power law: " + std::to_string(m_powerLawIndex) + " " + std::to_string(m_powerLawFloor) +
1403 " starting from block " + std::to_string(block0) + " " + std::to_string(gain0));
1404
1405
1406}
1407
1408INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_zeroAll)(const pcf::IndiProperty &ipRecv)
1409{
1410 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_zeroAll, ipRecv);
1411
1412 if(!ipRecv.find("request")) return 0;
1413
1414 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1415 {
1416 std::unique_lock<std::mutex> lock(m_indiMutex);
1417
1418 std::cerr << "Got zero all\n";
1419 m_gainsTarget.setZero();
1420 writeGains();
1421
1422 updateSwitchIfChanged(m_indiP_zeroAll, "request", pcf::IndiElement::Off, INDI_IDLE);
1423 }
1424
1425 return 0;
1426}
1427
1428INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleModeNo)(const pcf::IndiProperty &ipRecv)
1429{
1430 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleModeNo, ipRecv);
1431
1432 int target;
1433
1434 if( indiTargetUpdate( m_indiP_singleModeNo, target, ipRecv, true) < 0)
1435 {
1436 log<software_error>({__FILE__,__LINE__});
1437 return -1;
1438 }
1439
1440 setSingleModeNo(target);
1441
1442 return 0;
1443}
1444
1445INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleGain)(const pcf::IndiProperty &ipRecv)
1446{
1447 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleGain, ipRecv);
1448
1449 float target;
1450
1451 if( indiTargetUpdate( m_indiP_singleGain, target, ipRecv, true) < 0)
1452 {
1453 log<software_error>({__FILE__,__LINE__});
1454 return -1;
1455 }
1456
1457 setSingleGain(target);
1458
1459 return 0;
1460}
1461
1462INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleMC)(const pcf::IndiProperty &ipRecv)
1463{
1464 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleMC, ipRecv);
1465
1466 float target;
1467
1468 if( indiTargetUpdate( m_indiP_singleMC, target, ipRecv, true) < 0)
1469 {
1470 log<software_error>({__FILE__,__LINE__});
1471 return -1;
1472 }
1473
1474 setSingleMC(target);
1475
1476 return 0;
1477}
1478
1479INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawIndex)(const pcf::IndiProperty &ipRecv)
1480{
1481 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawIndex, ipRecv);
1482
1483 float target;
1484
1485 if( indiTargetUpdate( m_indiP_powerLawIndex, target, ipRecv, true) < 0)
1486 {
1487 log<software_error>({__FILE__,__LINE__});
1488 return -1;
1489 }
1490
1491 powerLawIndex(target);
1492
1493 return 0;
1494}
1495
1496INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawFloor)(const pcf::IndiProperty &ipRecv)
1497{
1498 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawFloor, ipRecv);
1499
1500 float target;
1501
1502 if( indiTargetUpdate( m_indiP_powerLawFloor, target, ipRecv, true) < 0)
1503 {
1504 log<software_error>({__FILE__,__LINE__});
1505 return -1;
1506 }
1507
1508 powerLawFloor(target);
1509
1510 return 0;
1511}
1512
1513INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawSet)(const pcf::IndiProperty &ipRecv)
1514{
1515 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawSet, ipRecv);
1516
1517 if(!ipRecv.find("request")) return 0;
1518
1519 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1520 {
1521 std::unique_lock<std::mutex> lock(m_indiMutex);
1522
1523 std::cerr << "Got Power Law\n";
1524 powerLawSet();
1525
1526 updateSwitchIfChanged(m_indiP_powerLawSet, "request", pcf::IndiElement::Off, INDI_IDLE);
1527 }
1528
1529 return 0;
1530}
1531
1533 const pcf::IndiProperty &ipRecv
1534 )
1535{
1536 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1538}
1539
1540int userGainCtrl::newCallBack_blockGains( const pcf::IndiProperty &ipRecv )
1541{
1542 if(ipRecv.getDevice() != m_configName)
1543 {
1544 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1545 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1546 #endif
1547
1548 return -1;
1549 }
1550
1551 if(ipRecv.getName().find("block") != 0)
1552 {
1553 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1554 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1555 #endif
1556
1557 return -1;
1558 }
1559
1560 if(ipRecv.getName().find("_gain") != 7)
1561 {
1562 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1563 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1564 #endif
1565
1566 return -1;
1567 }
1568
1569 if(ipRecv.getName().size() != 12)
1570 {
1571 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1572 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1573 #endif
1574
1575 return -1;
1576 }
1577
1578 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1579 return 0;
1580 #endif
1581
1582 int n = std::stoi(ipRecv.getName().substr(5,2));
1583
1584 float current = -1;
1585 float target = -1;
1586
1587 if(ipRecv.find("current"))
1588 {
1589 current = ipRecv["current"].get<double>();
1590 }
1591
1592 if(ipRecv.find("target"))
1593 {
1594 target = ipRecv["target"].get<double>();
1595 }
1596
1597 if(target == -1) target = current;
1598
1599 if(target == -1)
1600 {
1601 return 0;
1602 }
1603
1604 updateIfChanged(m_indiP_blockGains[n], "target", target);
1605
1606 return setBlockGain(n, target);
1607
1608}
1609
1611 const pcf::IndiProperty &ipRecv
1612 )
1613{
1614 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1616}
1617
1618int userGainCtrl::newCallBack_blockMCs( const pcf::IndiProperty &ipRecv )
1619{
1620 if(ipRecv.getDevice() != m_configName)
1621 {
1622 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1623 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1624 #endif
1625
1626 return -1;
1627 }
1628
1629 if(ipRecv.getName().find("block") != 0)
1630 {
1631 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1632 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1633 #endif
1634
1635 return -1;
1636 }
1637
1638 if(ipRecv.getName().find("_multcoeff") != 7)
1639 {
1640 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1641 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1642 #endif
1643
1644 return -1;
1645 }
1646
1647 if(ipRecv.getName().size() != 17)
1648 {
1649 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1650 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1651 #endif
1652
1653 return -1;
1654 }
1655
1656 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1657 return 0;
1658 #endif
1659
1660 int n = std::stoi(ipRecv.getName().substr(5,2));
1661
1662 float current = -1;
1663 float target = -1;
1664
1665 if(ipRecv.find("current"))
1666 {
1667 current = ipRecv["current"].get<double>();
1668 }
1669
1670 if(ipRecv.find("target"))
1671 {
1672 target = ipRecv["target"].get<double>();
1673 }
1674
1675 if(target == -1) target = current;
1676
1677 if(target == -1)
1678 {
1679 return 0;
1680 }
1681
1682 updateIfChanged(m_indiP_blockMCs[n], "target", target);
1683
1684 return setBlockMC(n, target);
1685
1686}
1687
1689 const pcf::IndiProperty &ipRecv
1690 )
1691{
1692 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1694}
1695
1696int userGainCtrl::newCallBack_blockLimits( const pcf::IndiProperty &ipRecv )
1697{
1698 if(ipRecv.getDevice() != m_configName)
1699 {
1700 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1701 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1702 #endif
1703
1704 return -1;
1705 }
1706
1707 if(ipRecv.getName().find("block") != 0)
1708 {
1709 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1710 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1711 #endif
1712
1713 return -1;
1714 }
1715
1716 if(ipRecv.getName().find("_limit") != 7)
1717 {
1718 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1719 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1720 #endif
1721
1722 return -1;
1723 }
1724
1725 if(ipRecv.getName().size() != 13)
1726 {
1727 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1728 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1729 #endif
1730
1731 return -1;
1732 }
1733
1734 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1735 return 0;
1736 #endif
1737
1738
1739 int n = std::stoi(ipRecv.getName().substr(5,2));
1740
1741 float current = -1;
1742 float target = -1;
1743
1744 if(ipRecv.find("current"))
1745 {
1746 current = ipRecv["current"].get<double>();
1747 }
1748
1749 if(ipRecv.find("target"))
1750 {
1751 target = ipRecv["target"].get<double>();
1752 }
1753
1754 if(target == -1) target = current;
1755
1756 if(target == -1)
1757 {
1758 return 0;
1759 }
1760
1761 updateIfChanged(m_indiP_blockLimits[n], "target", target);
1762
1763 return setBlockLimit(n, target);
1764
1765}
1766
1767inline
1772
1773inline
1775{
1776 return recordBlockGains(true);
1777}
1778
1779inline
1781{
1782 static std::vector<float> modeBlockGains;
1783 static std::vector<uint8_t> modeBlockGainsConstant;
1784
1785 static std::vector<float> modeBlockMCs;
1786 static std::vector<uint8_t> modeBlockMCsConstant;
1787
1788 static std::vector<float> modeBlockLims;
1789 static std::vector<uint8_t> modeBlockLimsConstant;
1790
1791 if(!force)
1792 {
1793 if(!(m_modeBlockGains == modeBlockGains)) force = true;
1794 }
1795
1796 if(!force)
1797 {
1799 }
1800
1801 if(!force)
1802 {
1803 if(!(m_modeBlockMCs == modeBlockMCs)) force = true;
1804 }
1805
1806 if(!force)
1807 {
1809 }
1810
1811 if(!force)
1812 {
1813 if(!(m_modeBlockLims == modeBlockLims)) force = true;
1814 }
1815
1816 if(!force)
1817 {
1819 }
1820
1821 if(force)
1822 {
1830 }
1831
1832 return 0;
1833}
1834
1835} //namespace app
1836} //namespace MagAOX
1837
1838#endif //userGainCtrl_hpp
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.
std::string m_configName
The name of the configuration file (minus .conf).
Definition MagAOXApp.hpp:83
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 m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
std::unordered_map< std::string, indiCallBack > m_indiNewCallBacks
Map to hold the NewProperty indiCallBacks for this App, with fast lookup by property name.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
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.
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.
uint32_t m_height
The height of the images in the stream.
IMAGE m_imageStream
The ImageStreamIO shared memory buffer.
int appShutdown()
Shuts down the shmimMonitor thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
size_t m_typeSize
The size of the type, in bytes. Result of sizeof.
std::vector< std::string > m_modeBlockNames
pcf::IndiProperty m_indiP_zeroAll
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_powerLawFloor)
static int st_newCallBack_blockLimits(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for block limits.
virtual int appShutdown()
Shutdown the app.
mx::improc::eigenImage< realT > m_mcsTarget
The target gains.
int m_totalNModes
The total number of WFS modes in the calib.
int newCallBack_blockLimits(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block limits.
int recordBlockGains(bool force=false)
std::vector< float > m_modeBlockGains
realT(* mc_pixget)(void *, size_t)
mx::improc::eigenImage< realT > m_mcsCurrent
Pointer to a function to extract the image data as our desired type realT.
pcf::IndiProperty m_indiP_powerLawFloor
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_singleMC)
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_zeroAll)
static int st_newCallBack_blockGains(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for block gains.
dev::telemeter< userGainCtrl > telemeterT
int newCallBack_blockMCs(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block mult. coeff.s.
std::vector< pcf::IndiProperty > m_indiP_blockGains
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_powerLawIndex)
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_singleGain)
static int st_newCallBack_blockMCs(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for block mult. coeff.s.
~userGainCtrl() noexcept
D'tor, declared and defined for noexcept.
int setBlockLimit(int n, float l)
mx::improc::eigenImage< realT > m_limitsTarget
The target gains.
int allocate(const gainShmimT &dummy)
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_powerLawSet)
std::vector< uint8_t > m_modeBlockGainsConstant
std::vector< uint16_t > m_modeBlockN
std::vector< pcf::IndiProperty > m_indiP_blockMCs
int setBlockMC(int n, float mc)
pcf::IndiProperty m_indiP_modes
int setBlockGain(int n, float g)
pcf::IndiProperty m_indiP_singleModeNo
std::vector< uint8_t > m_modeBlockMCsConstant
INDI_NEWCALLBACK_DECL(userGainCtrl, m_indiP_singleModeNo)
std::vector< float > m_modeBlockLims
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
realT(* limit_pixget)(void *, size_t)
dev::shmimMonitor< userGainCtrl, limitShmimT > limitShmimMonitorT
realT(* pixget)(void *, size_t)
int processImage(void *curr_src, const gainShmimT &dummy)
pcf::IndiProperty m_indiP_singleMC
float realT
Floating point type in which to do all calculations.
dev::shmimMonitor< userGainCtrl, gainShmimT > shmimMonitorT
pcf::IndiProperty m_indiP_powerLawSet
pcf::IndiProperty m_indiP_powerLawIndex
std::vector< float > m_modeBlockMCs
virtual int appLogic()
Implementation of the FSM for userGainCtrl.
virtual int appStartup()
Startup function.
int recordTelem(const telem_blockgains *)
std::vector< pcf::IndiProperty > m_indiP_blockLimits
std::vector< uint8_t > m_modeBlockLimsConstant
int newCallBack_blockGains(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block gain request.
std::vector< uint16_t > m_modeBlockStart
Pointer to a function to extract the image data as our desired type realT.
mx::improc::eigenImage< realT > m_gainsCurrent
The current gains.
mx::improc::eigenImage< realT > m_gainsTarget
The target gains.
mx::improc::eigenImage< realT > m_limitsCurrent
Pointer to a function to extract the image data as our desired type realT.
pcf::IndiProperty m_indiP_singleGain
mx::fits::fitsFile< float > m_ff
dev::shmimMonitor< userGainCtrl, multcoeffShmimT > mcShmimMonitorT
#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.
@ READY
The device is ready for operation, but is not operating.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:27
int addNumberElement(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="")
Add a standard INDI Number element.
Definition indiUtils.hpp:59
uint16_t modesAtBlock(uint16_t b)
uint16_t modesInBlock(uint16_t b)
Calculate the number of modes in 1 block.
const pcf::IndiProperty & ipRecv
int blockModes(std::vector< uint16_t > &blocks, std::vector< std::string > &names, uint16_t Nmodes, uint16_t Nzern, bool splitTT)
Calculate the number of blocks and the number of modes per block.
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:26
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
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.
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
Software ERR log entry.
Log entry recording electronics rack temperature.