7 #ifndef userGainCtrl_hpp
8 #define userGainCtrl_hpp
12 #include <mx/improc/eigenCube.hpp>
13 #include <mx/improc/eigenImage.hpp>
14 #include <mx/ioutils/fits/fitsFile.hpp>
16 #include "../../libMagAOX/libMagAOX.hpp"
17 #include "../../magaox_git_version.h"
26 int16_t N = 2* (2*b+1 + 1);
28 return (N+1)*(N+1) - 1;
52 std::vector<std::string> & names,
58 double Nblocksd = (sqrt(1.0+Nmodes) - 1)/4.;
59 int Nblocks = Nblocksd;
61 if(Nblocks < Nblocksd)
77 names.push_back(
"Tip");
84 names.push_back(
"Tip");
86 names.push_back(
"Tilt");
93 names.push_back(
"Tip/Tilt");
102 names.push_back(
"Focus");
108 blocks.push_back(Nzern - 3);
109 names.push_back(
"Z " + std::to_string(4)+
"-" + std::to_string(Nzern));
110 tot += blocks.back();
118 for(
size_t n=0; n < blocks.size(); ++n)
123 if(sum != Nmodes && sum != Nzern)
133 while(currb < Nblocks)
144 uint16_t Nthis = NAtThis - tot;
146 if(tot + Nthis > Nmodes)
148 Nthis = Nmodes - tot;
156 blocks.push_back(Nthis);
157 names.push_back(
"Block " + std::to_string(blocks.size()-1));
163 for(
size_t n=0; n < blocks.size(); ++n)
194 return "multcoeffShmim";
199 return "multcoeffShmim";
303 mx::fits::fitsFile<float>
m_ff;
441 const pcf::IndiProperty &
ipRecv
458 const pcf::IndiProperty &
ipRecv
475 const pcf::IndiProperty &
ipRecv
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.");
528 _config(
m_nZern,
"blocks.nZern");
566 log<software_error>({__FILE__,__LINE__});
575 createStandardIndiNumber<int>(
m_indiP_singleGain,
"singleGain", 0, 1.5 ,0,
"%0.2f",
"");
580 createStandardIndiNumber<int>(
m_indiP_singleMC,
"singleMC", 0, 1.0 ,0,
"%0.2f",
"");
598 log<software_error>({__FILE__,__LINE__});
657 log<software_error>({__FILE__, __LINE__});
666 log<software_error>({__FILE__, __LINE__});
671 log<software_error>({__FILE__, __LINE__});
676 log<software_error>({__FILE__, __LINE__});
726 log<text_log>(
"loading new gain block structure");
738 std::unique_lock<std::mutex> indilock(
m_indiMutex);
744 for(
int n=0; n < 100; ++n)
747 snprintf(str,
sizeof(str),
"%02d", n);
748 std::string en =
"block";
762 log<software_error>({__FILE__, __LINE__,
"failed to erase " +
m_indiP_blockGains[n].createUniqueKey()});
776 log<software_error>({__FILE__, __LINE__,
"failed to erase " +
m_indiP_blockMCs[n].createUniqueKey()});
790 log<software_error>({__FILE__, __LINE__,
"failed to erase " +
m_indiP_blockLimits[n].createUniqueKey()});
801 for(
size_t n=0; n < Nb; ++n)
805 snprintf(str,
sizeof(str),
"%02d", nn);
806 std::string en =
"block";
832 static_cast<void>(dummy);
851 static_cast<void>(dummy);
861 data[nn] =
pixget(curr_src, nn);
881 bool constant =
true;
957 static_cast<void>(dummy);
963 mx::sys::milliSleep(100);
987 static_cast<void>(dummy);
1017 bool constant =
true;
1092 static_cast<void>(dummy);
1098 mx::sys::milliSleep(100);
1122 static_cast<void>(dummy);
1151 bool constant =
true;
1230 if(m_singleModeNo < 0 || m_singleModeNo >=
m_gainsCurrent.rows())
return -1;
1235 if(m_singleModeNo < 0 || m_singleModeNo >=
m_mcsCurrent.rows())
return -1;
1245 if(m_singleModeNo < 0 || m_singleModeNo >=
m_gainsCurrent.rows())
return -1;
1257 if(m_singleModeNo < 0 || m_singleModeNo >=
m_mcsCurrent.rows())
return -1;
1269 if(m_singleModeNo < 0 || m_singleModeNo >=
m_gainsCurrent.rows())
return;
1274 if(m_singleModeNo < 0 || m_singleModeNo >=
m_mcsCurrent.rows())
return;
1301 uint16_t block0 = 0;
1356 if(gain < 0) gain = 0;
1364 mx::sys::milliSleep(5);
1370 " starting from block " + std::to_string(block0) +
" " + std::to_string(gain0));
1379 if(!
ipRecv.find(
"request"))
return 0;
1381 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1383 std::unique_lock<std::mutex>
lock(m_indiMutex);
1386 m_gainsTarget.setZero();
1401 if( indiTargetUpdate( m_indiP_singleModeNo, target,
ipRecv,
true) < 0)
1403 log<software_error>({__FILE__,__LINE__});
1407 setSingleModeNo(target);
1418 if( indiTargetUpdate( m_indiP_singleGain, target,
ipRecv,
true) < 0)
1420 log<software_error>({__FILE__,__LINE__});
1424 setSingleGain(target);
1435 if( indiTargetUpdate( m_indiP_singleMC, target,
ipRecv,
true) < 0)
1437 log<software_error>({__FILE__,__LINE__});
1441 setSingleMC(target);
1452 if( indiTargetUpdate( m_indiP_powerLawIndex, target,
ipRecv,
true) < 0)
1454 log<software_error>({__FILE__,__LINE__});
1458 powerLawIndex(target);
1469 if( indiTargetUpdate( m_indiP_powerLawFloor, target,
ipRecv,
true) < 0)
1471 log<software_error>({__FILE__,__LINE__});
1475 powerLawFloor(target);
1484 if(!
ipRecv.find(
"request"))
return 0;
1486 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1488 std::unique_lock<std::mutex>
lock(m_indiMutex);
1500 const pcf::IndiProperty &
ipRecv
1511 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1512 log<software_error>({__FILE__, __LINE__,
"wrong INDI device"});
1518 if(
ipRecv.getName().find(
"block") != 0)
1520 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1521 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1527 if(
ipRecv.getName().find(
"_gain") != 7)
1529 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1530 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1536 if(
ipRecv.getName().size() != 12)
1538 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1539 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1545 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1549 int n = std::stoi(
ipRecv.getName().substr(5,2));
1554 if(
ipRecv.find(
"current"))
1556 current =
ipRecv[
"current"].get<
double>();
1559 if(
ipRecv.find(
"target"))
1561 target =
ipRecv[
"target"].get<
double>();
1564 if(target == -1) target = current;
1578 const pcf::IndiProperty &
ipRecv
1589 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1590 log<software_error>({__FILE__, __LINE__,
"wrong INDI device"});
1596 if(
ipRecv.getName().find(
"block") != 0)
1598 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1599 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1605 if(
ipRecv.getName().find(
"_multcoeff") != 7)
1607 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1608 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1614 if(
ipRecv.getName().size() != 17)
1616 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1617 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1623 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1627 int n = std::stoi(
ipRecv.getName().substr(5,2));
1632 if(
ipRecv.find(
"current"))
1634 current =
ipRecv[
"current"].get<
double>();
1637 if(
ipRecv.find(
"target"))
1639 target =
ipRecv[
"target"].get<
double>();
1642 if(target == -1) target = current;
1656 const pcf::IndiProperty &
ipRecv
1667 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1668 log<software_error>({__FILE__, __LINE__,
"wrong INDI device"});
1674 if(
ipRecv.getName().find(
"block") != 0)
1676 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1677 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1683 if(
ipRecv.getName().find(
"_limit") != 7)
1685 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1686 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1692 if(
ipRecv.getName().size() != 13)
1694 #ifndef XWCTEST_INDI_CALLBACK_VALIDATION
1695 log<software_error>({__FILE__, __LINE__,
"wrong INDI property"});
1701 #ifdef XWCTEST_INDI_CALLBACK_VALIDATION
1706 int n = std::stoi(
ipRecv.getName().substr(5,2));
1711 if(
ipRecv.find(
"current"))
1713 current =
ipRecv[
"current"].get<
double>();
1716 if(
ipRecv.find(
"target"))
1718 target =
ipRecv[
"target"].get<
double>();
1721 if(target == -1) target = current;
1749 static std::vector<float> modeBlockGains;
1750 static std::vector<uint8_t> modeBlockGainsConstant;
1752 static std::vector<float> modeBlockMCs;
1753 static std::vector<uint8_t> modeBlockMCsConstant;
1755 static std::vector<float> modeBlockLims;
1756 static std::vector<uint8_t> modeBlockLimsConstant;
The base-class for MagAO-X applications.
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).
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.
int appStartup()
Startup function.
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
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.
uint8_t m_dataType
The ImageStreamIO type code.
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
int setSingleModeNo(int m)
realT(* mc_pixget)(void *, size_t)
void powerLawIndex(float pli)
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.
friend class userGainCtrl_test
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
void powerLawFloor(float plf)
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.
int setSingleGain(float g)
realT(* limit_pixget)(void *, size_t)
dev::shmimMonitor< userGainCtrl, limitShmimT > limitShmimMonitorT
userGainCtrl()
Default c'tor.
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 *)
virtual void loadConfig()
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.
int setSingleMC(float mc)
std::vector< uint16_t > m_modeBlockStart
Pointer to a function to extract the image data as our desired type realT.
std::mutex m_modeBlockMutex
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
virtual void setupConfig()
#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.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
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.
uint16_t modesAtBlock(uint16_t b)
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
uint16_t modesInBlock(uint16_t b)
Calculate the number of modes in 1 block.
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
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)
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
A device base class which saves telemetry.
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()
Log entry recording electronics rack temperature.