9 #ifndef streamWriter_hpp
10 #define streamWriter_hpp
13 #include <ImageStreamIO/ImageStruct.h>
14 #include <ImageStreamIO/ImageStreamIO.h>
16 #include <xrif/xrif.h>
18 #include <mx/sys/timeUtils.hpp>
20 #include "../../libMagAOX/libMagAOX.hpp"
21 #include "../../magaox_git_version.h"
25 #include "../../magaox_git_version.h"
29 #define NOT_WRITING (0)
30 #define START_WRITING (1)
32 #define STOP_WRITING (3)
328 config.add(
"writer.savePath",
"",
"writer.savePath", argType::Required,
"writer",
"savePath",
false,
"string",
"The absolute path where images are saved. Will use MagAO-X default if not set.");
330 config.add(
"writer.circBuffLength",
"",
"writer.circBuffLength", argType::Required,
"writer",
"circBuffLength",
false,
"size_t",
"The length in frames of the circular buffer. Should be an integer multiple of and larger than writeChunkLength.");
332 config.add(
"writer.writeChunkLength",
"",
"writer.writeChunkLength", argType::Required,
"writer",
"writeChunkLength",
false,
"size_t",
"The length in frames of the chunks to write to disk. Should be smaller than circBuffLength.");
334 config.add(
"writer.threadPrio",
"",
"writer.threadPrio", argType::Required,
"writer",
"threadPrio",
false,
"int",
"The real-time priority of the stream writer thread.");
336 config.add(
"writer.cpuset",
"",
"writer.cpuset", argType::Required,
"writer",
"cpuset",
false,
"int",
"The cpuset for the writer thread.");
338 config.add(
"writer.compress",
"",
"writer.compress", argType::Required,
"writer",
"compress",
false,
"bool",
"Flag to set whether compression is used. Default true.");
340 config.add(
"writer.lz4accel",
"",
"writer.lz4accel", argType::Required,
"writer",
"lz4accel",
false,
"int",
"The LZ4 acceleration parameter. Larger is faster, but lower compression.");
342 config.add(
"writer.outName",
"",
"writer.outName", argType::Required,
"writer",
"outName",
false,
"int",
"The name to use for output files. Default is the shmimName.");
344 config.add(
"framegrabber.shmimName",
"",
"framegrabber.shmimName", argType::Required,
"framegrabber",
"shmimName",
false,
"int",
"The name of the stream to monitor. From /tmp/shmimName.im.shm.");
347 config.add(
"framegrabber.semaphoreNumber",
"",
"framegrabber.semaphoreNumber", argType::Required,
"framegrabber",
"semaphoreNumber",
false,
"int",
"The semaphore to wait on. Default is 7.");
349 config.add(
"framegrabber.semWait",
"",
"framegrabber.semWait", argType::Required,
"framegrabber",
"semWait",
false,
"int",
"The time in nsec to wait on the semaphore. Max is 999999999. Default is 5e8 nsec.");
351 config.add(
"framegrabber.threadPrio",
"",
"framegrabber.threadPrio", argType::Required,
"framegrabber",
"threadPrio",
false,
"int",
"The real-time priority of the framegrabber thread.");
353 config.add(
"framegrabber.cpuset",
"",
"framegrabber.cpuset", argType::Required,
"framegrabber",
"cpuset",
false,
"string",
"The cpuset for the framegrabber thread.");
380 config(
m_semWait,
"framegrabber.semWait");
405 if( mkdir(
m_rawimageDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 )
409 std::stringstream logss;
410 logss <<
"Failed to create image directory (" <<
m_rawimageDir <<
"). Errno says: " << strerror(errno);
411 log<software_critical>({__FILE__, __LINE__, errno, 0, logss.str()});
427 indi::addNumberElement<float>(
m_indiP_xrifStats,
"ratio", 0, 1.0, 0.0,
"%0.2f",
"Compression Ratio");
429 indi::addNumberElement<float>(
m_indiP_xrifStats,
"differenceMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Differencing Rate [MB/sec]");
431 indi::addNumberElement<float>(
m_indiP_xrifStats,
"reorderMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Reordering Rate [MB/sec]");
433 indi::addNumberElement<float>(
m_indiP_xrifStats,
"compressMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Compression Rate [MB/sec]");
435 indi::addNumberElement<float>(
m_indiP_xrifStats,
"encodeMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Total Encoding Rate [MB/sec]");
437 indi::addNumberElement<float>(
m_indiP_xrifStats,
"differenceFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Differencing Rate [f.p.s.]");
439 indi::addNumberElement<float>(
m_indiP_xrifStats,
"reorderFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Reordering Rate [f.p.s.]");
441 indi::addNumberElement<float>(
m_indiP_xrifStats,
"compressFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Compression Rate [f.p.s.]");
443 indi::addNumberElement<float>(
m_indiP_xrifStats,
"encodeFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Total Encoding Rate [f.p.s.]");
453 if(sem_init(&
m_swSemaphore, 0,0) < 0)
return log<software_critical, -1>({__FILE__, __LINE__, errno,0,
"Initializing S.W. semaphore"});
458 return log<
software_critical, -1>({__FILE__,__LINE__,
"Write chunk length is not a divisor of circular buffer length."});
462 if(
initialize_xrif() < 0) log<software_critical,-1>({__FILE__, __LINE__});
492 if(pthread_tryjoin_np(
m_fgThread.native_handle(),0) == 0)
494 log<software_error>({__FILE__, __LINE__,
"framegrabber thread has exited"});
500 log<software_error>({__FILE__, __LINE__,
"streamwriter thread has exited"});
506 if(pthread_tryjoin_np(
m_swThread.native_handle(),0) == 0)
508 log<software_error>({__FILE__, __LINE__,
"stream thread has exited"});
514 log<software_error>({__FILE__, __LINE__,
"streamwriter thread has exited"});
531 log<software_error>({__FILE__, __LINE__});
582 xrif_error_t rv = xrif_new(&
m_xrif);
583 if( rv != XRIF_NOERROR )
585 return log<
software_critical, -1>({__FILE__,__LINE__, 0, rv,
"xrif handle allocation or initialization error."});
590 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_PREVIOUS, XRIF_REORDER_BYTEPACK, XRIF_COMPRESS_LZ4);
591 if( rv != XRIF_NOERROR )
593 return log<
software_critical, -1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
599 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
600 if( rv != XRIF_NOERROR )
602 return log<
software_critical, -1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
608 m_xrif_header = (
char *) malloc( XRIF_HEADER_SIZE *
sizeof(
char));
611 return log<
software_critical, -1>({__FILE__,__LINE__, errno, 0,
"xrif header allocation failed."});
615 if( rv != XRIF_NOERROR )
617 return log<
software_critical, -1>({__FILE__,__LINE__, 0, rv,
"xrif handle allocation or initialization error."});
621 rv = xrif_configure(
m_xrif_timing, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
622 if( rv != XRIF_NOERROR )
624 return log<
software_critical, -1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
631 return log<
software_critical, -1>({__FILE__,__LINE__, errno, 0,
"xrif header allocation failed."});
640 struct sigaction act;
644 act.sa_flags = SA_SIGINFO;
649 if( sigaction(SIGSEGV, &act, 0) < 0 )
651 std::string logss =
"Setting handler for SIGSEGV failed. Errno says: ";
652 logss += strerror(errno);
654 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
660 if( sigaction(SIGBUS, &act, 0) < 0 )
662 std::string logss =
"Setting handler for SIGBUS failed. Errno says: ";
663 logss += strerror(errno);
665 log<software_error>({__FILE__, __LINE__, errno, 0,logss});
690 static_cast<void>(signum);
691 static_cast<void>(siginf);
692 static_cast<void>(ucont);
738 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_PREVIOUS, XRIF_REORDER_BYTEPACK, XRIF_COMPRESS_LZ4);
739 if( rv != XRIF_NOERROR )
741 return log<
software_critical,-1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
747 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
748 if( rv != XRIF_NOERROR )
750 return log<
software_critical,-1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
755 if( rv != XRIF_NOERROR )
760 rv = xrif_allocate_raw(
m_xrif);
761 if( rv != XRIF_NOERROR )
766 rv = xrif_allocate_reordered(
m_xrif);
767 if( rv != XRIF_NOERROR )
773 rv = xrif_configure(
m_xrif_timing, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
774 if( rv != XRIF_NOERROR )
776 return log<
software_critical,-1>({__FILE__,__LINE__, 0, rv,
"xrif handle configuration error."});
780 if( rv != XRIF_NOERROR )
786 if( rv != XRIF_NOERROR )
792 if( rv != XRIF_NOERROR )
832 sem_t * sem {
nullptr};
841 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
842 SM_fd = open(SM_fname, O_RDWR);
855 if( ImageStreamIO_openIm(&image,
m_shmimName.c_str()) == 0)
859 ImageStreamIO_closeIm(&image);
867 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
870 int rv = stat(SM_fname, &buffer);
874 log<software_critical>({__FILE__,__LINE__, errno,
"Could not get inode for " +
m_shmimName +
". Source process will need to be restarted."});
875 ImageStreamIO_closeIm(&image);
878 inode = buffer.st_ino;
893 ImageStreamIO_closeIm(&image);
902 log<software_critical>({__FILE__,__LINE__,
"No valid semaphore found for " +
m_shmimName +
". Source process will need to be restarted."});
917 if(image.md[0].naxis == 3)
919 length = image.md[0].size[2];
934 size_t snx, sny, snz;
942 uint64_t last_cnt0 = ((uint64_t) -1);
951 if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
953 log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
959 if(sem_timedwait(sem, &ts) == 0)
961 if(image.md[0].naxis > 2)
963 curr_image = image.md[0].cnt1;
967 atype = image.md[0].datatype;
968 snx = image.md[0].size[0];
969 sny = image.md[0].size[1];
970 if(image.md[0].naxis == 3)
972 snz = image.md[0].size[2];
991 new_cnt0 = image.cntarray[curr_image];
995 new_cnt0 = image.md[0].cnt0;
998 if(new_cnt0 == last_cnt0 )
1000 log<text_log>(
"semaphore raised but cnt0 has not changed -- we're probably getting behind",
logPrio::LOG_WARNING);
1006 if(new_cnt0 - last_cnt0 > 1)
1013 last_cnt0 = new_cnt0;
1025 curr_timing[0] = image.cntarray[curr_image];
1026 curr_timing[1] = image.atimearray[curr_image].tv_sec;
1027 curr_timing[2] = image.atimearray[curr_image].tv_nsec;
1028 curr_timing[3] = image.writetimearray[curr_image].tv_sec;
1029 curr_timing[4] = image.writetimearray[curr_image].tv_nsec;
1033 curr_timing[0] = image.md[0].cnt0;
1034 curr_timing[1] = image.md[0].atime.tv_sec;
1035 curr_timing[2] = image.md[0].atime.tv_nsec;
1036 curr_timing[3] = image.md[0].writetime.tv_sec;
1037 curr_timing[4] = image.md[0].writetime.tv_nsec;
1042 if(curr_timing[1] == 0)
1045 if(clock_gettime(CLOCK_REALTIME, &missing_ts) < 0)
1047 log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
1051 curr_timing[1] = missing_ts.tv_sec;
1052 curr_timing[2] = missing_ts.tv_nsec;
1056 if(curr_timing[3] == 0)
1058 curr_timing[3] = curr_timing[1];
1059 curr_timing[4] = curr_timing[2];
1082 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1102 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1120 if(image.md[0].sem <= 0)
break;
1123 if(errno == EINTR)
break;
1127 if(errno != ETIMEDOUT)
1129 log<software_error>({__FILE__, __LINE__,errno,
"sem_timedwait"});
1136 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
1137 SM_fd = open(SM_fname, O_RDWR);
1146 int rv = stat(SM_fname, &buffer);
1152 if(buffer.st_ino != inode)
1175 ImageStreamIO_closeIm(&image);
1198 ImageStreamIO_closeIm(&image);
1251 if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
1253 log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
1261 mx::sys::timespecAddNsec(ts,
m_semWait);
1271 if(errno == EINTR)
continue;
1275 if(errno != ETIMEDOUT)
1277 log<software_error>({__FILE__, __LINE__,errno,
"sem_timedwait"});
1304 timespec tw0, tw1, tw2;
1306 clock_gettime(CLOCK_REALTIME, &tw0);
1310 if(rv != XRIF_NOERROR)
1313 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif set size error. DATA POSSIBLY LOST"});
1317 if(rv != XRIF_NOERROR)
1320 log<software_error>({__FILE__,__LINE__, 0, rv,
"xrif set LZ4 acceleration error."});
1327 if(rv != XRIF_NOERROR)
1330 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif set size error. DATA POSSIBLY LOST."});
1334 if(rv != XRIF_NOERROR)
1337 log<software_error>({__FILE__,__LINE__, 0, rv,
"xrif set LZ4 acceleration error."});
1343 rv = xrif_encode(
m_xrif);
1344 if(rv != XRIF_NOERROR)
1347 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif encode error. DATA POSSIBLY LOST."});
1351 if(rv != XRIF_NOERROR)
1354 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif write header error. DATA POSSIBLY LOST."});
1358 if(rv != XRIF_NOERROR)
1361 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif encode error. DATA POSSIBLY LOST."});
1365 if(rv != XRIF_NOERROR)
1368 log<software_alert>({__FILE__,__LINE__, 0, rv,
"xrif write header error. DATA POSSIBLY LOST"});
1375 if(gmtime_r(&fts->tv_sec, &uttime) == 0)
1378 log<software_alert>({__FILE__,__LINE__,errno,0,
"gmtime_r error. possible loss of timing information."});
1383 uttime.tm_mon+1, uttime.tm_mday, uttime.tm_hour, uttime.tm_min, uttime.tm_sec,
static_cast<int>(fts->tv_nsec));
1385 if(rv !=
sizeof(
"YYYYMMDDHHMMSSNNNNNNNNN")-1)
1388 log<software_alert>({__FILE__,__LINE__, errno, rv,
"did not write enough chars to timestamp"});
1394 clock_gettime(CLOCK_REALTIME, &tw1);
1396 FILE * fp_xrif = fopen(
m_fname,
"wb");
1400 log<software_alert>({__FILE__,__LINE__,errno,0,
"failed to open file for writing"});
1408 size_t bw = fwrite(
m_xrif_header,
sizeof(uint8_t), XRIF_HEADER_SIZE, fp_xrif);
1410 if(bw != XRIF_HEADER_SIZE)
1412 log<software_alert>({__FILE__,__LINE__,errno, 0,
"failure writing header to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1416 bw = fwrite(
m_xrif->raw_buffer,
sizeof(uint8_t),
m_xrif->compressed_size, fp_xrif);
1418 if(bw !=
m_xrif->compressed_size)
1420 log<software_alert>({__FILE__,__LINE__,errno,0,
"failure writing data to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1425 if(bw != XRIF_HEADER_SIZE)
1427 log<software_alert>({__FILE__,__LINE__,errno, 0,
"failure writing timing header to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1434 log<software_alert>({__FILE__,__LINE__,errno,0,
"failure writing timing data to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1439 clock_gettime(CLOCK_REALTIME, &tw2);
1441 double wt = ( (double) tw2.tv_sec + ((
double) tw2.tv_nsec)/1e9) - ( (double) tw1.tv_sec + ((
double) tw1.tv_nsec)/1e9);
1462 if(!
ipRecv.find(
"toggle"))
return 0;
1469 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On && m_writing ==
NOT_WRITING)
1526 static int16_t lastState = -1;
1527 static uint64_t currSaveStart = -1;
1547 static uint32_t last_rawSize = -1;
1548 static uint32_t last_compressedSize = -1;
1549 static float last_encodeRate = -1;
1550 static float last_differenceRate = -1;
1551 static float last_reorderRate = -1;
1552 static float last_compressRate = -1;
1554 if(
m_xrif->raw_size != last_rawSize ||
m_xrif->compressed_size != last_compressedSize ||
m_xrif->encode_rate != last_encodeRate ||
m_xrif->difference_rate != last_differenceRate ||
1555 m_xrif->reorder_rate != last_reorderRate ||
m_xrif->compress_rate != last_compressRate || force)
1557 telem<telem_saving>({(uint32_t)
m_xrif->raw_size, (uint32_t)
m_xrif->compressed_size, (float)
m_xrif->encode_rate, (
float)
m_xrif->difference_rate, (float)
m_xrif->reorder_rate, (
float)
m_xrif->compress_rate});
1559 last_rawSize =
m_xrif->raw_size;
1560 last_compressedSize =
m_xrif->compressed_size;
1561 last_encodeRate =
m_xrif->encode_rate;
1562 last_differenceRate =
m_xrif->difference_rate;
1563 last_reorderRate =
m_xrif->reorder_rate;
1564 last_compressRate =
m_xrif->compress_rate;
The base-class for MagAO-X applications.
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.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int shutdown()
Get the value of the shutdown flag.
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 threadStart(std::thread &thrd, bool &thrdInit, pid_t &tpid, pcf::IndiProperty &thProp, int thrdPrio, const std::string &cpuset, const std::string &thrdName, thisPtr *thrdThis, Function &&thrdStart)
Start a thread, using this class's privileges to set priority, etc.
std::string MagAOXPath
The base path of the MagAO-X system.
bool m_powerMgtEnabled
Flag controls whether power mgt is used. Set this in the constructor of a derived app....
pcf::IndiProperty m_indiP_xrifStats
pcf::IndiProperty m_indiP_writing
std::thread m_fgThread
A separate thread for the actual framegrabbings.
int m_fgThreadPrio
Priority of the framegrabber thread, should normally be > 00.
pid_t m_fgThreadID
F.g. thread PID.
size_t m_circBuffLength
The length of the circular buffer, in frames.
int initialize_xrif()
Initialize the xrif system.
int recordTelem(const telem_saving_state *)
uint64_t * m_timingCircBuff
uint8_t m_dataType
The ImageStreamIO type code.
bool m_fgThreadInit
Synchronizer to ensure f.g. thread initializes before doing dangerous things.
int m_typeSize
The pixel byte depth.
xrif_t m_xrif_timing
The xrif compression handle for image data.
uint64_t m_currSaveStart
The circular buffer position at which to start saving.
virtual int appStartup()
Startup functions.
size_t m_writeChunkLength
The number of frames to write at a time.
size_t m_height
The height of the image.
uint64_t m_currSaveStopFrameNo
The frame number of the image at which saving stopped (for logging)
int allocate_circbufs()
Worker function to allocate the circular buffers.
void handlerSigSegv(int signum, siginfo_t *siginf, void *ucont)
Handles SIGSEGV and SIGBUS. Sets m_restart to true.
int m_swThreadPrio
Priority of the stream writer thread, should normally be > 0, and <= m_fgThreadPrio.
int recordSavingStats(bool force=false)
pcf::IndiProperty m_swThreadProp
The property to hold the s.w. thread details.
unsigned m_semWait
The time in nsec to wait on the semaphore. Max is 999999999. Default is 5e8 nsec.
std::thread m_swThread
A separate thread for the actual writing.
std::string m_fgCpuset
The cpuset for the framegrabber thread. Ignored if empty (the default).
virtual int appLogic()
Implementation of the FSM for the Siglent SDG.
static void fgThreadStart(streamWriter *s)
Thread starter, called by fgThreadStart on thread construction. Calls fgThreadExec.
std::string m_outName
The name to use for outputting files, Default is m_shmimName.
char * m_rawImageCircBuff
INDI_NEWCALLBACK_DECL(streamWriter, m_indiP_writing)
char * m_xrif_timing_header
Storage for the xrif image data file header.
~streamWriter() noexcept
Destructor.
int allocate_xrif()
Worker function to configure and allocate the xrif handles.
int setSigSegvHandler()
Sets the handler for SIGSEGV and SIGBUS.
std::string m_swCpuset
The cpuset for the framegrabber thread. Ignored if empty (the default).
xrif_t m_xrif
The xrif compression handle for image data.
streamWriter()
Default c'tor.
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
int m_semaphoreNumber
The image structure semaphore index.
std::string m_rawimageDir
The path where files will be saved.
static void _handlerSigSegv(int signum, siginfo_t *siginf, void *ucont)
The handler called when SIGSEGV or SIGBUS is received, which will be due to ImageStreamIO server rese...
int recordSavingState(bool force=false)
int m_writing
Controls whether or not images are being written, and sequences start and stop of writing.
uint64_t m_currSaveStartFrameNo
The frame number of the image at which saving started (for logging)
uint64_t m_currChunkStart
The circular buffer starting position of the current to-be-written chunk.
pid_t m_swThreadID
S.w. thread pid.
bool m_logSaveStart
Flag indicating that the start saving log should entry should be made.
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
pcf::IndiProperty m_fgThreadProp
The property to hold the f.g. thread details.
void swThreadExec()
Execute the stream writer main loop.
uint64_t m_nextChunkStart
The circular buffer starting position of the next to-be-written chunk.
static streamWriter * m_selfWriter
Static pointer to this (set in constructor). Used for getting out of the static SIGSEGV handler.
char * m_xrif_header
Storage for the xrif image data file header.
int doEncode()
Function called when semaphore is raised to do the encode and write.
static void swThreadStart(streamWriter *s)
Thread starter, called by swThreadStart on thread construction. Calls swThreadExec.
uint64_t m_currSaveStop
The circular buffer position at which to stop saving.
void fgThreadExec()
Execute the frame grabber main loop.
std::string m_shmimName
The name of the shared memory buffer.
dev::telemeter< streamWriter > telemeterT
size_t m_width
The width of the image.
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
sem_t m_swSemaphore
Semaphore used to synchronize the fg thread and the sw thread.
bool m_swThreadInit
Synchronizer to ensure s.w. thread initializes before doing dangerous things.
#define MAGAOX_rawimageRelPath
The relative path to the raw images directory.
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#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.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
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_VALIDATE_CALLBACK_PROPS(function, ipRecv)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
constexpr static logPrioT LOG_DEBUG
Used for debugging.
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
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.
A device 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.
Software CRITICAL log entry.