7 #ifndef shmimIntegrator_hpp
8 #define shmimIntegrator_hpp
12 #include <mx/improc/eigenCube.hpp>
13 #include <mx/improc/eigenImage.hpp>
15 #include "../../libMagAOX/libMagAOX.hpp"
16 #include "../../magaox_git_version.h"
339 config.add(
"integrator.nAverage",
"",
"integrator.nAverage", argType::Required,
"integrator",
"nAverage",
false,
"unsigned",
"The default number of frames to average. Default 10. Can be changed via INDI.");
340 config.add(
"integrator.fpsSource",
"",
"integrator.fpsSource", argType::Required,
"integrator",
"fpsSource",
false,
"string",
"Device name for getting fps if time-based averaging is used. This device should have *.fps.current.");
342 config.add(
"integrator.avgTime",
"",
"integrator.avgTime", argType::Required,
"integrator",
"avgTime",
false,
"float",
"If non zero, then m_nAverage adjusts automatically to keep a constant averaging time [sec]. Default 0. Can be changed via INDI.");
344 config.add(
"integrator.nUpdate",
"",
"integrator.nUpdate", argType::Required,
"integrator",
"nUpdate",
false,
"unsigned",
"The rate at which to update the average. If 0 < m_nUpdate < m_nAverage then this is a moving averager. Default 0. If 0, then it is a simple average.");
346 config.add(
"integrator.continuous",
"",
"integrator.continuous", argType::Required,
"integrator",
"continuous",
false,
"bool",
"Flag controlling whether averaging is continuous or only when triggered. Default true.");
347 config.add(
"integrator.running",
"",
"integrator.running", argType::Required,
"integrator",
"running",
false,
"bool",
"Flag controlling whether averaging is running at startup. Default true.");
349 config.add(
"integrator.stateSource",
"",
"integrator.stateSource", argType::Required,
"integrator",
"stateSource",
false,
"string",
"///< Device name for getting the state string for file management. This device should have *.state_string.current.");
350 config.add(
"integrator.fileSaver",
"",
"integrator.fileSaver", argType::Required,
"integrator",
"fileSaver",
false,
"bool",
"Flag controlling whether this saves and reloads files automatically. Default false.");
369 _config(
m_avgTime,
"integrator.avgTime");
370 _config(
m_nUpdate,
"integrator.nUpdate");
374 _config(
m_running,
"integrator.running");
392 createStandardIndiNumber<unsigned>(
m_indiP_nAverage,
"nAverage", 1, std::numeric_limits<unsigned>::max(), 1,
"%u");
398 log<software_error>({__FILE__,__LINE__});
402 createStandardIndiNumber<float>(
m_indiP_avgTime,
"avgTime", 0, std::numeric_limits<float>::max(),0 ,
"%0.1f");
408 log<software_error>({__FILE__,__LINE__});
412 createStandardIndiNumber<unsigned>(
m_indiP_nUpdate,
"nUpdate", 1, std::numeric_limits<unsigned>::max(), 1,
"%u");
418 log<software_error>({__FILE__,__LINE__});
425 log<software_error>({__FILE__,__LINE__});
454 log<software_error>({__FILE__,__LINE__});
463 if( mkdir(
m_fileSaveDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 )
467 std::stringstream logss;
468 logss <<
"Failed to create image directory (" <<
m_fileSaveDir <<
"). Errno says: " << strerror(errno);
469 log<software_critical>({__FILE__, __LINE__, errno, 0, logss.str()});
479 log<software_critical>({__FILE__, __LINE__, errno,0,
"Initializing S.M. semaphore"});
545 log<software_error>({__FILE__, __LINE__});
550 log<software_error>({__FILE__, __LINE__});
555 log<software_error>({__FILE__, __LINE__});
560 log<software_error>({__FILE__, __LINE__});
574 log<software_error>({__FILE__, __LINE__});
627 static_cast<void>(dummy);
672 log<software_error>({__FILE__, __LINE__,
"bad data type"});
715 static_cast<void>(dummy);
728 data[nn] +=
pixget(curr_src, nn);
756 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
779 clock_gettime(CLOCK_REALTIME, &fts);
783 if(gmtime_r(&fts.tv_sec, &uttime) == 0)
786 log<software_alert>({__FILE__,__LINE__,errno,0,
"gmtime_r error. possible loss of timing information."});
789 char cts[] =
"YYYYMMDDHHMMSSNNNNNNNNN";
790 int rv = snprintf(cts,
sizeof(cts),
"%04i%02i%02i%02i%02i%02i%09i", uttime.tm_year+1900,
791 uttime.tm_mon+1, uttime.tm_mday, uttime.tm_hour, uttime.tm_min, uttime.tm_sec,
static_cast<int>(fts.tv_nsec));
793 if(rv !=
sizeof(cts)-1)
796 log<software_alert>({__FILE__,__LINE__, errno, rv,
"did not write enough chars to timestamp"});
801 mx::fits::fitsFile<float> ff;
803 log<text_log>(
"Wrote " + fname);
816 data[nn] =
pixget(curr_src, nn);
860 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
873 static_cast<void>(dummy);
884 log<software_error>({__FILE__, __LINE__,
"bad data type"});
908 static_cast<void>(dummy);
926 static_cast<void>(dummy);
937 log<software_error>({__FILE__, __LINE__,
"bad data type"});
961 static_cast<void>(dummy);
983 long N = fnames.size();
984 for(
long n = N-1; n >= 0; --n)
986 std::string fn = mx::ioutils::pathStem(fnames[n]);
991 size_t ed = fn.find(
"__T");
992 if(ed == std::string::npos || ed - st < 2)
continue;
993 std::string stateStr = fn.substr(st,ed-st);
997 mx::fits::fitsFile<float> ff;
1028 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1079 if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
1081 log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
1121 if(
ipRecv.getName() != m_indiP_nAverage.getName())
1123 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
1129 if( indiTargetUpdate( m_indiP_nAverage, target,
ipRecv,
true) < 0)
1131 log<software_error>({__FILE__,__LINE__});
1135 m_nAverage = target;
1137 if(m_avgTime > 0 && m_fps > 0)
1139 m_avgTime = m_nAverage/m_fps;
1148 shmimMonitorT::m_restart =
true;
1157 if(
ipRecv.getName() != m_indiP_avgTime.getName())
1159 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
1165 if( indiTargetUpdate( m_indiP_avgTime, target,
ipRecv,
true) < 0)
1167 log<software_error>({__FILE__,__LINE__});
1176 shmimMonitorT::m_restart =
true;
1185 if(
ipRecv.getName() != m_indiP_nUpdate.getName())
1187 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
1193 if( indiTargetUpdate( m_indiP_nUpdate, target,
ipRecv,
true) < 0)
1195 log<software_error>({__FILE__,__LINE__});
1205 shmimMonitorT::m_restart =
true;
1214 if(
ipRecv.getName() != m_indiP_startAveraging.getName())
1216 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
1220 if(!
ipRecv.find(
"toggle"))
return 0;
1222 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off)
1224 std::unique_lock<std::mutex>
lock(m_indiMutex);
1233 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
1235 std::unique_lock<std::mutex>
lock(m_indiMutex);
1237 if(m_fileSaver && !m_continuous) m_stateStringChanged =
false;
1239 m_stateStringValidOnStart = m_stateStringValid;
1251 if(
ipRecv.getName() != m_indiP_fpsSource.getName())
1253 log<software_error>({__FILE__, __LINE__,
"Invalid INDI property."});
1257 if(
ipRecv.find(
"current") !=
true )
1262 std::lock_guard<std::mutex> guard(m_indiMutex);
1264 realT fps =
ipRecv[
"current"].get<
float>();
1269 std::cout <<
"Got fps: " << m_fps <<
"\n";
1270 shmimMonitorT::m_restart =
true;
1278 if(
ipRecv.getName() != m_indiP_stateSource.getName())
1280 log<software_error>({__FILE__, __LINE__,
"Invalid INDI property."});
1284 if(
ipRecv.find(
"valid") ==
true )
1286 bool stateStringValid;
1287 if(
ipRecv[
"valid"].get<std::string>() ==
"yes") stateStringValid =
true;
1288 else stateStringValid =
false;
1290 if(stateStringValid != m_stateStringValid) m_stateStringChanged =
true;
1292 m_stateStringValid = stateStringValid;
1295 if(
ipRecv.find(
"current") !=
true )
1302 std::lock_guard<std::mutex> guard(m_indiMutex);
1304 std::string ss =
ipRecv[
"current"].get<std::string>();
1306 if(ss != m_stateString)
1309 m_imageValid =
false;
1311 m_stateStringChanged =
true;
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).
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
std::string m_calibDir
The path to calibration files for MagAOX.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
int createROIndiText(pcf::IndiProperty &prop, const std::string &propName, const std::string &elName, const std::string &propLabel="", const std::string &propGroup="", const std::string &elLabel="")
Create a standard ReadOnly INDI Text property, with at least one element.
std::mutex m_indiMutex
Mutex for locking INDI communications.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
int appShutdown()
Shuts down the framegrabber thread.
int recordFGTimings(bool force=false)
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.
int updateINDI()
Update the INDI properties for this device controller.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_reconfig
Flag to set if a camera reconfiguration requires a framegrabber reset.
int appLogic()
Checks the framegrabber thread.
int appStartup()
Startup function.
uint32_t m_height
The height of the image, once deinterlaced etc.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
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.
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
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
virtual void setupConfig()
pcf::IndiProperty m_indiP_imageValid
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
dev::telemeter< shmimIntegrator > telemeterT
std::mutex m_darkMutex
Pointer to a function to extract the image data as our desired type realT.
pcf::IndiProperty m_indiP_nAverage
dev::frameGrabber< shmimIntegrator > frameGrabberT
int allocate(const dev::shmimT &dummy)
realT(* pixget)(void *, size_t)
INDI_SETCALLBACK_DECL(shmimIntegrator, m_indiP_fpsSource)
float fps()
Implementation of the framegrabber fps interface.
INDI_NEWCALLBACK_DECL(shmimIntegrator, m_indiP_nAverage)
int recordTelem(const telem_fgtimings *)
mx::improc::eigenCube< realT > m_accumImages
Cube used to accumulate images.
INDI_NEWCALLBACK_DECL(shmimIntegrator, m_indiP_avgTime)
float realT
Floating point type in which to do all calculations.
virtual void loadConfig()
friend class shmimIntegrator_test
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pcf::IndiProperty m_indiP_stateSource
std::string m_fileSaveDir
bool m_stateStringChanged
pcf::IndiProperty m_indiP_nUpdate
pcf::IndiProperty m_indiP_startAveraging
int reconfig()
Implementation of the framegrabber reconfig interface.
shmimIntegrator()
Pointer to a function to extract the image data as our desired type realT.
pcf::IndiProperty m_indiP_fps
this integrator's FPS
dev::shmimMonitor< shmimIntegrator, dark2ShmimT > dark2MonitorT
realT(* dark_pixget)(void *, size_t)
float m_fps
Current FPS from the FPS source.
bool m_continuous
Set to false in configuration to have this run once then stop until triggered.
unsigned m_nUpdate
The rate at which to update the average. If 0 < m_nUpdate < m_nAverage then this is a moving averager...
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
INDI_SETCALLBACK_DECL(shmimIntegrator, m_indiP_stateSource)
bool m_running
Set to false in configuration to have it not start averaging until triggered.
pcf::IndiProperty m_indiP_avgTime
pcf::IndiProperty m_indiP_fpsSource
bool m_stateStringValidOnStart
mx::improc::eigenImage< realT > m_dark2Image
Pointer to a function to extract the image data as our desired type realT.
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
realT(* dark2_pixget)(void *, size_t)
int processImage(void *curr_src, const dev::shmimT &dummy)
virtual int appStartup()
Startup function.
sem_t m_smSemaphore
Semaphore used to synchronize the fg thread and the sm thread.
unsigned m_nAverageDefault
The number of frames to average. Default 10.
std::string m_stateString
dev::shmimMonitor< shmimIntegrator > shmimMonitorT
std::string m_stateSource
The source of the state string used for file management.
virtual int appShutdown()
Shutdown the app.
virtual int appLogic()
Implementation of the FSM for shmimIntegrator.
INDI_NEWCALLBACK_DECL(shmimIntegrator, m_indiP_nUpdate)
float m_avgTime
If non zero, then m_nAverage adjusts automatically to keep a constant averaging time [sec]....
INDI_NEWCALLBACK_DECL(shmimIntegrator, m_indiP_startAveraging)
~shmimIntegrator() noexcept
D'tor, declared and defined for noexcept.
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
mx::improc::eigenImage< realT > m_darkImage
std::string m_fpsSource
Device name for getting fps if time-based averaging is used. This device should have *....
dev::shmimMonitor< shmimIntegrator, darkShmimT > darkMonitorT
bool m_fileSaver
Set to true in configuration to have this save and reload files automatically.
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber these images can not be flipped
mx::improc::eigenImage< realT > m_avgImage
The average image.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
@ READY
The device is ready for operation, but is not operating.
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.
const pcf::IndiProperty & ipRecv
INDI_SETCALLBACK_DEFN(adcTracker, m_indiP_teldata)(const pcf
updateIfChanged(m_indiP_angle, "target", m_angle)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
std::unique_lock< std::mutex > lock(m_indiMutex)
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
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.
Log entry recording framegrabber timings.