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 ///@}
270
271 mx::improc::eigenImage<realT> m_gainsCurrent; ///< The current gains.
272 mx::improc::eigenImage<realT> m_gainsTarget; ///< The target gains.
273
274 realT (*pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
275
276 mx::improc::eigenImage<realT> m_mcsCurrent; ///< The current gains.
277 mx::improc::eigenImage<realT> m_mcsTarget; ///< The target gains.
278
279 realT (*mc_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
280
281 mx::improc::eigenImage<realT> m_limitsCurrent; ///< The current gains.
282 mx::improc::eigenImage<realT> m_limitsTarget; ///< The target gains.
283
284 realT (*limit_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
285
286 std::vector<uint16_t> m_modeBlockStart;
287 std::vector<uint16_t> m_modeBlockN;
288 std::vector<std::string> m_modeBlockNames;
289
290 int m_totalNModes {0}; ///< The total number of WFS modes in the calib.
291
292 std::vector<float> m_modeBlockGains;
293 std::vector<uint8_t> m_modeBlockGainsConstant;
294
295 std::vector<float> m_modeBlockMCs;
296 std::vector<uint8_t> m_modeBlockMCsConstant;
297
298 std::vector<float> m_modeBlockLims;
299 std::vector<uint8_t> m_modeBlockLimsConstant;
300
302
303 mx::fits::fitsFile<float> m_ff;
304
306
308 float m_powerLawFloor {0.05};
309
310public:
311 /// Default c'tor.
312 userGainCtrl();
313
314 /// D'tor, declared and defined for noexcept.
317
318 virtual void setupConfig();
319
320 /// Implementation of loadConfig logic, separated for testing.
321 /** This is called by loadConfig().
322 */
323 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
324
325 virtual void loadConfig();
326
327 /// Startup function
328 /**
329 *
330 */
331 virtual int appStartup();
332
333 /// Implementation of the FSM for userGainCtrl.
334 /**
335 * \returns 0 on no critical error
336 * \returns -1 on an error requiring shutdown
337 */
338 virtual int appLogic();
339
340 /// Shutdown the app.
341 /**
342 *
343 */
344 virtual int appShutdown();
345
346protected:
347
348 //int checkAOCalib(); ///< Test if the AO calib is accessible.
349
350 //int getAOCalib();
351
352 int getModeBlocks();
353
354 int allocate( const gainShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
355
356 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
357 const gainShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
358 );
359
360 int writeGains();
361
362 int setBlockGain( int n,
363 float g
364 );
365
366 int allocate( const multcoeffShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
367
368 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
369 const multcoeffShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
370 );
371
372 int writeMCs();
373
374 int setBlockMC( int n,
375 float mc
376 );
377
378 int allocate( const limitShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
379
380 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
381 const limitShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
382 );
383
384 int writeLimits();
385
386 int setBlockLimit( int n,
387 float l
388 );
389
390 int setSingleModeNo (int m);
391
392 int setSingleGain( float g );
393
394 int setSingleMC( float mc );
395
396 void updateSingles();
397
398 void powerLawIndex( float pli );
399
400 void powerLawFloor( float plf );
401
402 void powerLawSet();
403
404 pcf::IndiProperty m_indiP_modes;
405
406 pcf::IndiProperty m_indiP_zeroAll;
407
408 std::vector<pcf::IndiProperty> m_indiP_blockGains;
409 std::vector<pcf::IndiProperty> m_indiP_blockMCs;
410 std::vector<pcf::IndiProperty> m_indiP_blockLimits;
411
412 pcf::IndiProperty m_indiP_singleModeNo;
413 pcf::IndiProperty m_indiP_singleGain;
414 pcf::IndiProperty m_indiP_singleMC;
415
416 pcf::IndiProperty m_indiP_powerLawIndex;
417 pcf::IndiProperty m_indiP_powerLawFloor;
418 pcf::IndiProperty m_indiP_powerLawSet;
419
420public:
421
423
425
427
429
433
434 /// The static callback function to be registered for block gains
435 /** Dispatches to the relevant handler
436 *
437 * \returns 0 on success.
438 * \returns -1 on error.
439 */
440 static int st_newCallBack_blockGains( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
441 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
442 );
443
444 /// Callback to process a NEW block gain request
445 /**
446 * \returns 0 on success.
447 * \returns -1 on error.
448 */
449 int newCallBack_blockGains( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
450
451 /// The static callback function to be registered for block mult. coeff.s
452 /** Dispatches to the relevant handler
453 *
454 * \returns 0 on success.
455 * \returns -1 on error.
456 */
457 static int st_newCallBack_blockMCs( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
458 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
459 );
460
461 /// Callback to process a NEW block mult. coeff.s
462 /**
463 * \returns 0 on success.
464 * \returns -1 on error.
465 */
466 int newCallBack_blockMCs( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
467
468 /// The static callback function to be registered for block limits
469 /** Dispatches to the relevant handler
470 *
471 * \returns 0 on success.
472 * \returns -1 on error.
473 */
474 static int st_newCallBack_blockLimits( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
475 const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
476 );
477
478 /// Callback to process a NEW block limits
479 /**
480 * \returns 0 on success.
481 * \returns -1 on error.
482 */
483 int newCallBack_blockLimits( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
484
485 /** \name Telemeter Interface
486 *
487 * @{
488 */
489 int checkRecordTimes();
490
491 int recordTelem( const telem_blockgains * );
492
493 int recordBlockGains( bool force = false );
494
495 ///@}
496};
497
498inline
499userGainCtrl::userGainCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
500{
501
505
506 return;
507}
508
509inline
511{
515
516 config.add("loop.number", "", "loop.number", argType::Required, "loop", "number", false, "int", "The loop number");
517 config.add("blocks.splitTT", "", "blocks.splitTT", argType::Required, "blocks", "splitTT", false, "bool", "If true, the first block is split into two modes.");
518 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.");
519
521}
522
523inline
524int userGainCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
525{
526 _config(m_loopNumber, "loop.number");
527 _config(m_splitTT, "blocks.splitTT");
528 _config(m_nZern, "blocks.nZern");
529
530 shmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mgainfact";
532
533 mcShmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mmultfact";
535
536 limitShmimMonitorT::m_shmimName = "aol" + std::to_string(m_loopNumber) + "_mlimitfact";
538
540 {
541 log<text_log>("Error during telemeter config", logPrio::LOG_CRITICAL);
542 m_shutdown = true;
543 }
544
545 return 0;
546}
547
548inline
550{
551 loadConfigImpl(config);
552}
553
554inline
556{
557 createROIndiNumber( m_indiP_modes, "modes", "Loop Modes", "Loop Controls");
558 indi::addNumberElement(m_indiP_modes, "total", 0, 1, 25000, "Total Modes");
559 indi::addNumberElement(m_indiP_modes, "blocks", 0, 1, 99, "Mode Blocks");
561
562
565 {
567 return -1;
568 }
569
570 createStandardIndiNumber<int>( m_indiP_singleModeNo, "singleModeNo", 0, 2400 ,0, "%0d", "");
571 m_indiP_singleModeNo["current"].set(m_singleModeNo);
574
575 createStandardIndiNumber<int>( m_indiP_singleGain, "singleGain", 0, 1.5 ,0, "%0.2f", "");
576 m_indiP_singleGain["current"].set(1);
577 m_indiP_singleGain["target"].set(1);
579
580 createStandardIndiNumber<int>( m_indiP_singleMC, "singleMC", 0, 1.0 ,0, "%0.2f", "");
581 m_indiP_singleMC["current"].set(1);
582 m_indiP_singleMC["target"].set(1);
584
585 createStandardIndiNumber<int>( m_indiP_powerLawIndex, "pwrlaw_index", 0, 10.0 ,0, "%0.2f", "");
589
590 createStandardIndiNumber<int>( m_indiP_powerLawFloor, "pwrlaw_floor", 0, 1.0 ,0, "%0.2f", "");
594
597 {
599 return -1;
600 }
601
603 {
604 return log<software_error,-1>({__FILE__, __LINE__});
605 }
606
608 {
609 return log<software_error,-1>({__FILE__, __LINE__});
610 }
611
613 {
614 return log<software_error,-1>({__FILE__, __LINE__});
615 }
616
617 if(telemeterT::appStartup() < 0)
618 {
619 return log<software_error,-1>({__FILE__,__LINE__});
620 }
621
623
624 return 0;
625}
626
627inline
629{
630 if( shmimMonitorT::appLogic() < 0)
631 {
632 return log<software_error,-1>({__FILE__,__LINE__});
633 }
634
636 {
637 return log<software_error,-1>({__FILE__,__LINE__});
638 }
639
641 {
642 return log<software_error,-1>({__FILE__,__LINE__});
643 }
644
647 {
650 if(state() == stateCodes::READY) state(stateCodes::OPERATING); //we just progress all the way through to operating so shmimMonitor will go.
651 }
652
654 {
655 if(telemeterT::appLogic() < 0)
656 {
658 return 0;
659 }
660 }
661
662 std::unique_lock<std::mutex> lock(m_indiMutex);
663
665 {
667 }
668
670 {
672 }
673
675 {
677 }
678
679 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
680 {
682 }
683
684 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
685 {
687 }
688
689 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
690 {
692 }
693
695
696 return 0;
697}
698
699inline
710
711
712inline
714{
716
717 uint16_t Nb = m_modeBlockN.size();
718
719 m_modeBlockStart.resize(m_modeBlockN.size());
720 m_modeBlockStart[0] = 0;
721 for(size_t n = 1; n < m_modeBlockN.size(); ++n)
722 {
724 }
725
726 log<text_log>("loading new gain block structure");
727
728 m_modeBlockGains.resize(Nb);
730
731 m_modeBlockMCs.resize(Nb);
733
734 m_modeBlockLims.resize(Nb);
736
737 //-- modify INDI vars --
738 std::unique_lock<std::mutex> indilock(m_indiMutex);
739
741 m_indiP_modes["blocks"] = m_modeBlockStart.size();
742
743 //First just delete all existing blockXX elements
744 for(int n=0; n < 100; ++n)
745 {
746 char str[16];
747 snprintf(str, sizeof(str), "%02d", n);
748 std::string en = "block";
749 en += str;
750
751 if(m_indiP_modes.find(en)) m_indiP_modes.remove(en);
752 }
753
754 //Erase existing block gains
755 if(m_indiP_blockGains.size() > 0)
756 {
757 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
758 {
759 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockGains[n]);
760 if(!m_indiNewCallBacks.erase(m_indiP_blockGains[n].createUniqueKey()))
761 {
762 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockGains[n].createUniqueKey()});
763 }
764 }
765 }
766 m_indiP_blockGains.clear();
767
768 //Erase existing block mult. coeffs
769 if(m_indiP_blockMCs.size() > 0)
770 {
771 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
772 {
773 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockMCs[n]);
774 if(!m_indiNewCallBacks.erase(m_indiP_blockMCs[n].createUniqueKey()))
775 {
776 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockMCs[n].createUniqueKey()});
777 }
778 }
779 }
780 m_indiP_blockMCs.clear();
781
782 //Erase existing block limits
783 if(m_indiP_blockLimits.size() > 0)
784 {
785 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
786 {
787 if(m_indiDriver) m_indiDriver->sendDelProperty(m_indiP_blockLimits[n]);
788 if(!m_indiNewCallBacks.erase(m_indiP_blockLimits[n].createUniqueKey()))
789 {
790 log<software_error>({__FILE__, __LINE__, "failed to erase " + m_indiP_blockLimits[n].createUniqueKey()});
791 }
792 }
793 }
794 m_indiP_blockLimits.clear();
795
796 m_indiP_blockGains.resize(Nb);
797 m_indiP_blockMCs.resize(Nb);
798 m_indiP_blockLimits.resize(Nb);
799
800 //Then add in what we want.
801 for(size_t n=0; n < Nb; ++n)
802 {
803 char str[16];
804 int nn = n;
805 snprintf(str, sizeof(str), "%02d", nn);
806 std::string en = "block";
807 en += str;
808 indi::addNumberElement(m_indiP_modes, en, 0, 1, 99, "Block " + std::to_string(nn));
810
811 createStandardIndiNumber<float>( m_indiP_blockGains[n], en + "_gain", 0.0, 10.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Gain", "Loop Controls");
813 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockGains[n]);
814
815 createStandardIndiNumber<float>( m_indiP_blockMCs[n], en + "_multcoeff", 0.0, 1.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Mult. Coeff", "Loop Controls");
817 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockMCs[n]);
818
819 createStandardIndiNumber<float>( m_indiP_blockLimits[n], en + "_limit", 0.0, 100.0, 0.01, "%0.3f", m_modeBlockNames[n] + " Limit", "Loop Controls");
821 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_blockLimits[n]);
822 }
823
824 if(m_indiDriver) m_indiDriver->sendSetProperty (m_indiP_modes); //might not exist yet!
825
826 return 0;
827}
828
829inline
831{
832 static_cast<void>(dummy); //be unused
833
834 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
835
838
840
842
843 return 0;
844}
845
846inline
847int userGainCtrl::processImage( void * curr_src,
848 const gainShmimT & dummy
849 )
850{
851 static_cast<void>(dummy); //be unused
852
854
855 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
856
857 realT * data = m_gainsCurrent.data();
858
860 {
861 data[nn] = pixget(curr_src, nn);
862 }
863
864 //update blocks here.
865
866 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
867 {
868 double mng = 0;
869
870 int NN = 0;
871
872 for(int m =0; m < m_modeBlockN[n]; ++m)
873 {
874 if(m_modeBlockStart[n] + m >= m_gainsCurrent.rows()) break;
876 ++NN;
877 }
878
879 m_modeBlockGains[n] = mng / NN;
880
881 bool constant = true;
882
883 for(int m =0; m < m_modeBlockN[n]; ++m)
884 {
885 if(m_modeBlockStart[n] + m >= m_gainsCurrent.rows()) break;
887 {
888 constant = false;
889 break;
890 }
891 }
892
893 m_modeBlockGainsConstant[n] = constant;
894
895 }
896
897 for(size_t n=0; n < m_indiP_blockGains.size(); ++n)
898 {
900 }
901
902 lock.unlock();
903
905
906 return 0;
907}
908
909inline
911{
913 char * dest = static_cast<char *>(shmimMonitorT::m_imageStream.array.raw);
914
916
917 //Set the time of last write
919
920 //Set the image acquisition timestamp
922
923 //Update cnt0
925
926 //And post
929
930 return 0;
931}
932
934 float g
935 )
936{
937 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
938
940
941 //Apply a delta to each mode in the block
942 //to preserve intra-block differences
943 for(int m =0; m < m_modeBlockN[n]; ++m)
944 {
945 if(m_modeBlockStart[n] + m > m_gainsTarget.rows() -1) break;
947 }
948 //lock.unlock();
949 recordBlockGains(true);
950 writeGains();
951 return 0;
952}
953
954inline
956{
957 static_cast<void>(dummy); //be unused
958
959 int n = 0;
960
962 {
963 mx::sys::milliSleep(100);
964 ++n;
965 }
966
968 {
969 return -1;
970 }
971
972 std::unique_lock<std::mutex> lock(m_indiMutex);
973
976
978
979 return 0;
980}
981
982inline
983int userGainCtrl::processImage( void * curr_src,
984 const multcoeffShmimT & dummy
985 )
986{
987 static_cast<void>(dummy); //be unused
988
990
991 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
992
993 realT * data = m_mcsCurrent.data();
994
996 {
997 data[nn] = mc_pixget(curr_src, nn);
998 }
999
1000 //update blocks here.
1001
1002 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
1003 {
1004 double mng = 0;
1005
1006 int NN = 0;
1007 for(int m =0; m < m_modeBlockN[n]; ++m)
1008 {
1009 if(m_modeBlockStart[n] + m >= m_mcsCurrent.rows()) break;
1011 ++NN;
1012 }
1013
1014 m_modeBlockMCs[n] = mng / NN;
1015
1016
1017 bool constant = true;
1018
1019 for(int m =0; m < m_modeBlockN[n]; ++m)
1020 {
1021 if(m_modeBlockStart[n] + m >= m_mcsCurrent.rows()) break;
1023 {
1024 constant = false;
1025 break;
1026 }
1027 }
1028
1029 m_modeBlockMCsConstant[n] = constant;
1030 }
1031
1032 for(size_t n=0; n < m_indiP_blockMCs.size(); ++n)
1033 {
1035 }
1036
1037 lock.unlock();
1038
1040
1041 return 0;
1042}
1043
1044inline
1046{
1048 char * dest = static_cast<char *>(mcShmimMonitorT::m_imageStream.array.raw);
1049
1051
1052 //Set the time of last write
1054
1055 //Set the image acquisition timestamp
1057
1058 //Update cnt0
1060
1061 //And post
1064
1065 return 0;
1066}
1067
1069 float mc
1070 )
1071{
1072 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1073
1075
1076 //Apply a delta to each mode in the block
1077 //to preserve intra-block differences
1078 for(int m =0; m < m_modeBlockN[n]; ++m)
1079 {
1080 if(m_modeBlockStart[n] + m > m_mcsTarget.rows() -1) break;
1082 }
1083 lock.unlock();
1084 recordBlockGains(true);
1085 writeMCs();
1086 return 0;
1087}
1088
1089inline
1091{
1092 static_cast<void>(dummy); //be unused
1093
1094 int n = 0;
1095
1097 {
1098 mx::sys::milliSleep(100);
1099 ++n;
1100 }
1101
1103 {
1104 return -1;
1105 }
1106
1107 std::unique_lock<std::mutex> lock(m_indiMutex);
1108
1111
1113
1114 return 0;
1115}
1116
1117inline
1118int userGainCtrl::processImage( void * curr_src,
1119 const limitShmimT & dummy
1120 )
1121{
1122 static_cast<void>(dummy); //be unused
1123
1125
1126 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1127
1128 realT * data = m_limitsCurrent.data();
1129
1131 {
1132 data[nn] = limit_pixget(curr_src, nn);
1133 }
1134
1135 //update blocks here.
1136
1137 for(size_t n =0; n < m_modeBlockStart.size(); ++n)
1138 {
1139 double mng = 0;
1140
1141 int NN = 0;
1142 for(int m =0; m < m_modeBlockN[n]; ++m)
1143 {
1144 if(m_modeBlockStart[n] + m >= m_limitsCurrent.rows()) break;
1146 ++NN;
1147 }
1148
1149 m_modeBlockLims[n] = mng / NN;
1150
1151 bool constant = true;
1152
1153 for(int m =0; m < m_modeBlockN[n]; ++m)
1154 {
1155 if(m_modeBlockStart[n] + m >= m_limitsCurrent.rows()) break;
1157 {
1158 constant = false;
1159 break;
1160 }
1161 }
1162
1163 m_modeBlockLimsConstant[n] = constant;
1164 }
1165
1166 for(size_t n=0; n < m_indiP_blockLimits.size(); ++n)
1167 {
1169 }
1170
1171 lock.unlock();
1172
1174
1175 return 0;
1176}
1177
1178inline
1180{
1182 char * dest = static_cast<char *>(limitShmimMonitorT::m_imageStream.array.raw);// + next_cnt1*m_width*m_height*m_typeSize;
1183
1185
1186 //Set the time of last write
1188
1189 //Set the image acquisition timestamp
1191
1192 //Update cnt0
1194
1195 //And post
1198
1199 return 0;
1200}
1201
1203 float l
1204 )
1205{
1206 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1207
1209
1210 //Apply a delta to each mode in the block
1211 //to preserve intra-block differences
1212 for(int m =0; m < m_modeBlockN[n]; ++m)
1213 {
1214 if(m_modeBlockStart[n] + m > m_limitsTarget.rows() -1) break;
1216 }
1217 lock.unlock();
1218 recordBlockGains(true);
1219 writeLimits();
1220
1221 return 0;
1222}
1223
1225{
1226 m_singleModeNo = m;
1227
1229
1231 float g = m_gainsCurrent (m_singleModeNo,0);
1232
1233 updateIfChanged(m_indiP_singleGain, std::vector<std::string>({"current", "target"}), std::vector<float>({g,g}));
1234
1236 float mc = m_mcsCurrent(m_singleModeNo,0);
1237
1238 updateIfChanged(m_indiP_singleMC, std::vector<std::string>({"current", "target"}), std::vector<float>({mc,mc}));
1239
1240 return 0;
1241}
1242
1244{
1247 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1249 lock.unlock();
1250 recordBlockGains(true);
1251 writeGains();
1252 return 0;
1253}
1254
1256{
1259 std::unique_lock<std::mutex> lock(m_modeBlockMutex);
1261 lock.unlock();
1262 recordBlockGains(true);
1263 writeMCs();
1264 return 0;
1265}
1266
1268{
1270 float g = m_gainsCurrent (m_singleModeNo,0);
1271
1272 updateIfChanged(m_indiP_singleGain, std::vector<std::string>({"current", "target"}), std::vector<float>({g,g}));
1273
1275 float mc = m_mcsCurrent(m_singleModeNo,0);
1276
1277 updateIfChanged(m_indiP_singleMC, std::vector<std::string>({"current", "target"}), std::vector<float>({mc,mc}));
1278
1279}
1280
1282{
1283 if(pli < 0)
1284 {
1285 pli = 0;
1286 }
1287
1289 updateIfChanged(m_indiP_powerLawIndex, std::vector<std::string>({"current", "target"}), std::vector<float>({pli,pli}));
1290}
1291
1293{
1295
1296 updateIfChanged(m_indiP_powerLawFloor, std::vector<std::string>({"current", "target"}), std::vector<float>({plf,plf}));
1297}
1298
1300{
1301 uint16_t block0 = 0;
1302
1303 if(m_nZern > 0)
1304 {
1305 if(m_nZern > 1)
1306 {
1307 if(m_splitTT)
1308 {
1309 block0 = 2;
1310 }
1311 else
1312 {
1313 block0 = 1;
1314 }
1315 }
1316
1317 if(m_nZern > 2)
1318 {
1319 ++block0;
1320 }
1321
1322 if(m_nZern > 3)
1323 {
1324 ++block0;
1325 }
1326 //Now have accounted for T/T and focus.
1327
1328 uint16_t currb = 1;
1329 while(modesAtBlock(currb) < m_nZern)
1330 {
1331 ++currb;
1332 ++block0;
1333 }
1334 }
1335
1336 if(block0 >= m_modeBlockStart.size())
1337 {
1338 return;
1339 }
1340
1341 if(m_powerLawIndex < 0)
1342 {
1343 m_powerLawIndex = 0;
1344 }
1345
1347 float gain0 = m_modeBlockGains[block0];
1348 for(size_t n=block0+1; n < m_modeBlockStart.size(); ++n)
1349 {
1350 float mode = m_modeBlockStart[n] + 0.5*m_modeBlockN[n];
1351
1352 float imd1=(mode-mode0)/(m_totalNModes-mode0);
1353 float imd2=pow(1.0-imd1, -m_powerLawIndex) * gain0;
1354 float gain=(1-m_powerLawFloor)*imd2+m_powerLawFloor;
1355
1356 if(gain < 0) gain = 0;
1357
1358 setBlockGain(n, gain);
1359
1360 //Now wait on the update, otherwise the next command can overwrite from m_gainsCurrent
1361 int nt = 0;
1362 while(fabs(m_modeBlockGains[n] - gain) > 1e-5 && nt < 100)
1363 {
1364 mx::sys::milliSleep(5);
1365 ++nt;
1366 }
1367 }
1368
1369 log<text_log>("Set power law: " + std::to_string(m_powerLawIndex) + " " + std::to_string(m_powerLawFloor) +
1370 " starting from block " + std::to_string(block0) + " " + std::to_string(gain0));
1371
1372
1373}
1374
1375INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_zeroAll)(const pcf::IndiProperty &ipRecv)
1376{
1377 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_zeroAll, ipRecv);
1378
1379 if(!ipRecv.find("request")) return 0;
1380
1381 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1382 {
1383 std::unique_lock<std::mutex> lock(m_indiMutex);
1384
1385 std::cerr << "Got zero all\n";
1386 m_gainsTarget.setZero();
1387 writeGains();
1388
1389 updateSwitchIfChanged(m_indiP_zeroAll, "request", pcf::IndiElement::Off, INDI_IDLE);
1390 }
1391
1392 return 0;
1393}
1394
1395INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleModeNo)(const pcf::IndiProperty &ipRecv)
1396{
1397 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleModeNo, ipRecv);
1398
1399 int target;
1400
1401 if( indiTargetUpdate( m_indiP_singleModeNo, target, ipRecv, true) < 0)
1402 {
1403 log<software_error>({__FILE__,__LINE__});
1404 return -1;
1405 }
1406
1407 setSingleModeNo(target);
1408
1409 return 0;
1410}
1411
1412INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleGain)(const pcf::IndiProperty &ipRecv)
1413{
1414 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleGain, ipRecv);
1415
1416 float target;
1417
1418 if( indiTargetUpdate( m_indiP_singleGain, target, ipRecv, true) < 0)
1419 {
1420 log<software_error>({__FILE__,__LINE__});
1421 return -1;
1422 }
1423
1424 setSingleGain(target);
1425
1426 return 0;
1427}
1428
1429INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_singleMC)(const pcf::IndiProperty &ipRecv)
1430{
1431 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_singleMC, ipRecv);
1432
1433 float target;
1434
1435 if( indiTargetUpdate( m_indiP_singleMC, target, ipRecv, true) < 0)
1436 {
1437 log<software_error>({__FILE__,__LINE__});
1438 return -1;
1439 }
1440
1441 setSingleMC(target);
1442
1443 return 0;
1444}
1445
1446INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawIndex)(const pcf::IndiProperty &ipRecv)
1447{
1448 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawIndex, ipRecv);
1449
1450 float target;
1451
1452 if( indiTargetUpdate( m_indiP_powerLawIndex, target, ipRecv, true) < 0)
1453 {
1454 log<software_error>({__FILE__,__LINE__});
1455 return -1;
1456 }
1457
1458 powerLawIndex(target);
1459
1460 return 0;
1461}
1462
1463INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawFloor)(const pcf::IndiProperty &ipRecv)
1464{
1465 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawFloor, ipRecv);
1466
1467 float target;
1468
1469 if( indiTargetUpdate( m_indiP_powerLawFloor, target, ipRecv, true) < 0)
1470 {
1471 log<software_error>({__FILE__,__LINE__});
1472 return -1;
1473 }
1474
1475 powerLawFloor(target);
1476
1477 return 0;
1478}
1479
1480INDI_NEWCALLBACK_DEFN(userGainCtrl, m_indiP_powerLawSet)(const pcf::IndiProperty &ipRecv)
1481{
1482 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_powerLawSet, ipRecv);
1483
1484 if(!ipRecv.find("request")) return 0;
1485
1486 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1487 {
1488 std::unique_lock<std::mutex> lock(m_indiMutex);
1489
1490 std::cerr << "Got Power Law\n";
1491 powerLawSet();
1492
1493 updateSwitchIfChanged(m_indiP_powerLawSet, "request", pcf::IndiElement::Off, INDI_IDLE);
1494 }
1495
1496 return 0;
1497}
1498
1500 const pcf::IndiProperty &ipRecv
1501 )
1502{
1503 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1505}
1506
1507int userGainCtrl::newCallBack_blockGains( const pcf::IndiProperty &ipRecv )
1508{
1509 if(ipRecv.getDevice() != m_configName)
1510 {
1511 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1512 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1513 #endif
1514
1515 return -1;
1516 }
1517
1518 if(ipRecv.getName().find("block") != 0)
1519 {
1520 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1521 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1522 #endif
1523
1524 return -1;
1525 }
1526
1527 if(ipRecv.getName().find("_gain") != 7)
1528 {
1529 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1530 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1531 #endif
1532
1533 return -1;
1534 }
1535
1536 if(ipRecv.getName().size() != 12)
1537 {
1538 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1539 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1540 #endif
1541
1542 return -1;
1543 }
1544
1545 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1546 return 0;
1547 #endif
1548
1549 int n = std::stoi(ipRecv.getName().substr(5,2));
1550
1551 float current = -1;
1552 float target = -1;
1553
1554 if(ipRecv.find("current"))
1555 {
1556 current = ipRecv["current"].get<double>();
1557 }
1558
1559 if(ipRecv.find("target"))
1560 {
1561 target = ipRecv["target"].get<double>();
1562 }
1563
1564 if(target == -1) target = current;
1565
1566 if(target == -1)
1567 {
1568 return 0;
1569 }
1570
1571 updateIfChanged(m_indiP_blockGains[n], "target", target);
1572
1573 return setBlockGain(n, target);
1574
1575}
1576
1578 const pcf::IndiProperty &ipRecv
1579 )
1580{
1581 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1583}
1584
1585int userGainCtrl::newCallBack_blockMCs( const pcf::IndiProperty &ipRecv )
1586{
1587 if(ipRecv.getDevice() != m_configName)
1588 {
1589 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1590 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1591 #endif
1592
1593 return -1;
1594 }
1595
1596 if(ipRecv.getName().find("block") != 0)
1597 {
1598 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1599 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1600 #endif
1601
1602 return -1;
1603 }
1604
1605 if(ipRecv.getName().find("_multcoeff") != 7)
1606 {
1607 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1608 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1609 #endif
1610
1611 return -1;
1612 }
1613
1614 if(ipRecv.getName().size() != 17)
1615 {
1616 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1617 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1618 #endif
1619
1620 return -1;
1621 }
1622
1623 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1624 return 0;
1625 #endif
1626
1627 int n = std::stoi(ipRecv.getName().substr(5,2));
1628
1629 float current = -1;
1630 float target = -1;
1631
1632 if(ipRecv.find("current"))
1633 {
1634 current = ipRecv["current"].get<double>();
1635 }
1636
1637 if(ipRecv.find("target"))
1638 {
1639 target = ipRecv["target"].get<double>();
1640 }
1641
1642 if(target == -1) target = current;
1643
1644 if(target == -1)
1645 {
1646 return 0;
1647 }
1648
1649 updateIfChanged(m_indiP_blockMCs[n], "target", target);
1650
1651 return setBlockMC(n, target);
1652
1653}
1654
1656 const pcf::IndiProperty &ipRecv
1657 )
1658{
1659 userGainCtrl * _app = static_cast<userGainCtrl *>(app);
1661}
1662
1663int userGainCtrl::newCallBack_blockLimits( const pcf::IndiProperty &ipRecv )
1664{
1665 if(ipRecv.getDevice() != m_configName)
1666 {
1667 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1668 log<software_error>({__FILE__, __LINE__, "wrong INDI device"});
1669 #endif
1670
1671 return -1;
1672 }
1673
1674 if(ipRecv.getName().find("block") != 0)
1675 {
1676 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1677 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1678 #endif
1679
1680 return -1;
1681 }
1682
1683 if(ipRecv.getName().find("_limit") != 7)
1684 {
1685 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1686 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1687 #endif
1688
1689 return -1;
1690 }
1691
1692 if(ipRecv.getName().size() != 13)
1693 {
1694 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1695 log<software_error>({__FILE__, __LINE__, "wrong INDI property"});
1696 #endif
1697
1698 return -1;
1699 }
1700
1701 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1702 return 0;
1703 #endif
1704
1705
1706 int n = std::stoi(ipRecv.getName().substr(5,2));
1707
1708 float current = -1;
1709 float target = -1;
1710
1711 if(ipRecv.find("current"))
1712 {
1713 current = ipRecv["current"].get<double>();
1714 }
1715
1716 if(ipRecv.find("target"))
1717 {
1718 target = ipRecv["target"].get<double>();
1719 }
1720
1721 if(target == -1) target = current;
1722
1723 if(target == -1)
1724 {
1725 return 0;
1726 }
1727
1728 updateIfChanged(m_indiP_blockLimits[n], "target", target);
1729
1730 return setBlockLimit(n, target);
1731
1732}
1733
1734inline
1739
1740inline
1742{
1743 return recordBlockGains(true);
1744}
1745
1746inline
1748{
1749 static std::vector<float> modeBlockGains;
1750 static std::vector<uint8_t> modeBlockGainsConstant;
1751
1752 static std::vector<float> modeBlockMCs;
1753 static std::vector<uint8_t> modeBlockMCsConstant;
1754
1755 static std::vector<float> modeBlockLims;
1756 static std::vector<uint8_t> modeBlockLimsConstant;
1757
1758 if(!force)
1759 {
1760 if(!(m_modeBlockGains == modeBlockGains)) force = true;
1761 }
1762
1763 if(!force)
1764 {
1766 }
1767
1768 if(!force)
1769 {
1770 if(!(m_modeBlockMCs == modeBlockMCs)) force = true;
1771 }
1772
1773 if(!force)
1774 {
1776 }
1777
1778 if(!force)
1779 {
1780 if(!(m_modeBlockLims == modeBlockLims)) force = true;
1781 }
1782
1783 if(!force)
1784 {
1786 }
1787
1788 if(force)
1789 {
1797 }
1798
1799 return 0;
1800}
1801
1802} //namespace app
1803} //namespace MagAOX
1804
1805#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.
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.
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.
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
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:28
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:63
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:24
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.