9 #ifndef streamWriter_hpp
10 #define streamWriter_hpp
12 #include <ImageStreamIO/ImageStruct.h>
13 #include <ImageStreamIO/ImageStreamIO.h>
15 #include <xrif/xrif.h>
17 #include <mx/sys/timeUtils.hpp>
19 #include "../../libMagAOX/libMagAOX.hpp"
20 #include "../../magaox_git_version.h"
22 #define NOT_WRITING (0)
23 #define START_WRITING (1)
25 #define STOP_WRITING (3)
318 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.");
320 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.");
322 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.");
324 config.add(
"writer.maxChunkTime",
"",
"writer.maxChunkTime", argType::Required,
"writer",
"maxChunkTime",
false,
"float",
"The max length in seconds of the chunks to write to disk. Default is 60 sec.");
326 config.add(
"writer.threadPrio",
"",
"writer.threadPrio", argType::Required,
"writer",
"threadPrio",
false,
"int",
"The real-time priority of the stream writer thread.");
328 config.add(
"writer.cpuset",
"",
"writer.cpuset", argType::Required,
"writer",
"cpuset",
false,
"int",
"The cpuset for the writer thread.");
330 config.add(
"writer.compress",
"",
"writer.compress", argType::Required,
"writer",
"compress",
false,
"bool",
"Flag to set whether compression is used. Default true.");
332 config.add(
"writer.lz4accel",
"",
"writer.lz4accel", argType::Required,
"writer",
"lz4accel",
false,
"int",
"The LZ4 acceleration parameter. Larger is faster, but lower compression.");
334 config.add(
"writer.outName",
"",
"writer.outName", argType::Required,
"writer",
"outName",
false,
"int",
"The name to use for output files. Default is the shmimName.");
336 config.add(
"framegrabber.shmimName",
"",
"framegrabber.shmimName", argType::Required,
"framegrabber",
"shmimName",
false,
"int",
"The name of the stream to monitor. From /tmp/shmimName.im.shm.");
338 config.add(
"framegrabber.semaphoreNumber",
"",
"framegrabber.semaphoreNumber", argType::Required,
"framegrabber",
"semaphoreNumber",
false,
"int",
"The semaphore to wait on. Default is 7.");
340 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.");
342 config.add(
"framegrabber.threadPrio",
"",
"framegrabber.threadPrio", argType::Required,
"framegrabber",
"threadPrio",
false,
"int",
"The real-time priority of the framegrabber thread.");
344 config.add(
"framegrabber.cpuset",
"",
"framegrabber.cpuset", argType::Required,
"framegrabber",
"cpuset",
false,
"string",
"The cpuset for the framegrabber thread.");
391 if (mkdir(
m_rawimageDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
395 std::stringstream logss;
396 logss <<
"Failed to create image directory (" <<
m_rawimageDir <<
"). Errno says: " << strerror(errno);
397 log<software_critical>({__FILE__, __LINE__, errno, 0, logss.str()});
411 indi::addNumberElement<float>(
m_indiP_xrifStats,
"ratio", 0, 1.0, 0.0,
"%0.2f",
"Compression Ratio");
413 indi::addNumberElement<float>(
m_indiP_xrifStats,
"differenceMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Differencing Rate [MB/sec]");
415 indi::addNumberElement<float>(
m_indiP_xrifStats,
"reorderMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Reordering Rate [MB/sec]");
417 indi::addNumberElement<float>(
m_indiP_xrifStats,
"compressMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Compression Rate [MB/sec]");
419 indi::addNumberElement<float>(
m_indiP_xrifStats,
"encodeMBsec", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Total Encoding Rate [MB/sec]");
421 indi::addNumberElement<float>(
m_indiP_xrifStats,
"differenceFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Differencing Rate [f.p.s.]");
423 indi::addNumberElement<float>(
m_indiP_xrifStats,
"reorderFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Reordering Rate [f.p.s.]");
425 indi::addNumberElement<float>(
m_indiP_xrifStats,
"compressFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Compression Rate [f.p.s.]");
427 indi::addNumberElement<float>(
m_indiP_xrifStats,
"encodeFPS", 0, std::numeric_limits<float>::max(), 0.0,
"%0.2f",
"Total Encoding Rate [f.p.s.]");
438 return log<software_critical, -1>({__FILE__, __LINE__, errno, 0,
"Initializing S.W. semaphore"});
443 return log<
software_critical, -1>({__FILE__, __LINE__,
"Write chunk length is not a divisor of circular buffer length."});
447 log<software_critical, -1>({__FILE__, __LINE__});
474 if (pthread_tryjoin_np(
m_fgThread.native_handle(), 0) == 0)
476 log<software_error>({__FILE__, __LINE__,
"framegrabber thread has exited"});
482 log<software_error>({__FILE__, __LINE__,
"framegrabber thread has exited"});
488 if (pthread_tryjoin_np(
m_swThread.native_handle(), 0) == 0)
490 log<software_error>({__FILE__, __LINE__,
"stream thread has exited"});
496 log<software_error>({__FILE__, __LINE__,
"streamwriter thread has exited"});
513 log<software_error>({__FILE__, __LINE__});
566 xrif_error_t rv = xrif_new(&
m_xrif);
567 if (rv != XRIF_NOERROR)
569 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle allocation or initialization error."});
574 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_PREVIOUS, XRIF_REORDER_BYTEPACK, XRIF_COMPRESS_LZ4);
575 if (rv != XRIF_NOERROR)
577 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
583 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
584 if (rv != XRIF_NOERROR)
586 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
591 m_xrif_header = (
char *)malloc(XRIF_HEADER_SIZE *
sizeof(
char));
594 return log<
software_critical, -1>({__FILE__, __LINE__, errno, 0,
"xrif header allocation failed."});
598 if (rv != XRIF_NOERROR)
600 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle allocation or initialization error."});
604 rv = xrif_configure(
m_xrif_timing, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
605 if (rv != XRIF_NOERROR)
607 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
614 return log<
software_critical, -1>({__FILE__, __LINE__, errno, 0,
"xrif header allocation failed."});
622 struct sigaction act;
626 act.sa_flags = SA_SIGINFO;
631 if (sigaction(SIGSEGV, &act, 0) < 0)
633 std::string logss =
"Setting handler for SIGSEGV failed. Errno says: ";
634 logss += strerror(errno);
636 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
642 if (sigaction(SIGBUS, &act, 0) < 0)
644 std::string logss =
"Setting handler for SIGBUS failed. Errno says: ";
645 logss += strerror(errno);
647 log<software_error>({__FILE__, __LINE__, errno, 0, logss});
668 static_cast<void>(signum);
669 static_cast<void>(siginf);
670 static_cast<void>(ucont);
714 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_PREVIOUS, XRIF_REORDER_BYTEPACK, XRIF_COMPRESS_LZ4);
715 if (rv != XRIF_NOERROR)
717 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
723 rv = xrif_configure(
m_xrif, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
724 if (rv != XRIF_NOERROR)
726 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
731 if (rv != XRIF_NOERROR)
736 rv = xrif_allocate_raw(
m_xrif);
737 if (rv != XRIF_NOERROR)
742 rv = xrif_allocate_reordered(
m_xrif);
743 if (rv != XRIF_NOERROR)
745 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif_allocate_reordered error."});
749 rv = xrif_configure(
m_xrif_timing, XRIF_DIFFERENCE_NONE, XRIF_REORDER_NONE, XRIF_COMPRESS_NONE);
750 if (rv != XRIF_NOERROR)
752 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif handle configuration error."});
756 if (rv != XRIF_NOERROR)
762 if (rv != XRIF_NOERROR)
768 if (rv != XRIF_NOERROR)
770 return log<
software_critical, -1>({__FILE__, __LINE__, 0, rv,
"xrif_allocate_reordered error."});
814 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
815 SM_fd = open(SM_fname, O_RDWR);
829 if (ImageStreamIO_openIm(&image,
m_shmimName.c_str()) == 0)
833 ImageStreamIO_closeIm(&image);
841 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
844 int rv = stat(SM_fname, &buffer);
848 log<software_critical>({__FILE__, __LINE__, errno,
"Could not get inode for " +
m_shmimName +
". Source process will need to be restarted."});
849 ImageStreamIO_closeIm(&image);
852 inode = buffer.st_ino;
869 ImageStreamIO_closeIm(&image);
878 log<software_critical>({__FILE__, __LINE__,
"No valid semaphore found for " +
m_shmimName +
". Source process will need to be restarted."});
893 if (image.md[0].naxis == 3)
895 length = image.md[0].size[2];
913 size_t snx, sny, snz;
921 if (image.md[0].naxis > 2)
923 curr_image = image.md[0].cnt1;
935 last_cnt0 = image.cntarray[curr_image];
939 last_cnt0 = image.md[0].cnt0;
944 bool restartWriting =
false;
952 if(sem_timedwait(sem, &ts) == 0)
954 if (image.md[0].naxis > 2)
956 curr_image = image.md[0].cnt1;
963 atype = image.md[0].datatype;
964 snx = image.md[0].size[0];
965 sny = image.md[0].size[1];
966 if (image.md[0].naxis == 3)
968 snz = image.md[0].size[2];
988 new_cnt0 = image.cntarray[curr_image];
992 new_cnt0 = image.md[0].cnt0;
996 std::cerr <<
"new_cnt0: " << new_cnt0 <<
"\n";
1000 if (new_cnt0 == last_cnt0)
1002 log<text_log>(
"semaphore raised but cnt0 has not changed -- we're probably getting behind",
logPrio::LOG_WARNING);
1011 if (new_cnt0 - last_cnt0 > 1)
1018 last_cnt0 = new_cnt0;
1029 curr_timing[0] = image.cntarray[curr_image];
1030 curr_timing[1] = image.atimearray[curr_image].tv_sec;
1031 curr_timing[2] = image.atimearray[curr_image].tv_nsec;
1032 curr_timing[3] = image.writetimearray[curr_image].tv_sec;
1033 curr_timing[4] = image.writetimearray[curr_image].tv_nsec;
1037 curr_timing[0] = image.md[0].cnt0;
1038 curr_timing[1] = image.md[0].atime.tv_sec;
1039 curr_timing[2] = image.md[0].atime.tv_nsec;
1040 curr_timing[3] = image.md[0].writetime.tv_sec;
1041 curr_timing[4] = image.md[0].writetime.tv_nsec;
1045 if (curr_timing[1] == 0)
1048 if (clock_gettime(CLOCK_REALTIME, &missing_ts) < 0)
1050 log<software_critical>({__FILE__, __LINE__, errno, 0,
"clock_gettime"});
1054 curr_timing[1] = missing_ts.tv_sec;
1055 curr_timing[2] = missing_ts.tv_nsec;
1059 if (curr_timing[3] == 0)
1061 curr_timing[3] = curr_timing[1];
1062 curr_timing[4] = curr_timing[2];
1065 m_currImageTime = 1.0 * curr_timing[3] + (1.0 * curr_timing[4]) / 1e9;
1082 log<saving_start>({1, new_cnt0});
1086 restartWriting =
false;
1104 << new_cnt0 <<
"\n";
1110 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1134 << new_cnt0 <<
"\n";
1140 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1145 restartWriting =
true;
1156 std::cerr << __FILE__ <<
" " << __LINE__ <<
" STOP_WRITING\n";
1162 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1165 restartWriting =
false;
1194 std::cerr << __FILE__ <<
" " << __LINE__ <<
" TIMEOUT WRITING " <<
" "
1196 << last_cnt0 <<
"\n";
1202 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1207 restartWriting =
true;
1218 std::cerr << __FILE__ <<
" " << __LINE__ <<
" TIMEOUT STOP_WRITING\n";
1224 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1227 restartWriting =
false;
1233 if (image.md[0].sem <= 0)
1246 if (errno != ETIMEDOUT)
1248 log<software_error>({__FILE__, __LINE__, errno,
"sem_timedwait"});
1255 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname),
m_shmimName.c_str());
1256 SM_fd = open(SM_fname, O_RDWR);
1265 int rv = stat(SM_fname, &buffer);
1271 if (buffer.st_ino != inode)
1274 std::cerr <<
"Restarting due to inode . . . \n";
1294 std::cerr << __FILE__ <<
" " << __LINE__ <<
" WRITING ON RESTART " << last_cnt0 <<
"\n";
1298 log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
1310 std::cerr << __FILE__ <<
" " << __LINE__ <<
" WAITING TO FINISH WRITING " << last_cnt0 <<
"\n";
1334 ImageStreamIO_closeIm(&image);
1361 ImageStreamIO_closeIm(&image);
1412 if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
1414 log<software_critical>({__FILE__, __LINE__, errno, 0,
"clock_gettime"});
1428 log<software_critical>({__FILE__, __LINE__,
"error encoding data"});
1443 if (errno != ETIMEDOUT)
1445 log<software_error>({__FILE__, __LINE__, errno,
"sem_timedwait"});
1474 std::cerr <<
"nFrames: " << nFrames <<
"\n";
1479 if (rv != XRIF_NOERROR)
1482 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif set size error. DATA POSSIBLY LOST"});
1486 if (rv != XRIF_NOERROR)
1489 log<software_error>({__FILE__, __LINE__, 0, rv,
"xrif set LZ4 acceleration error."});
1495 rv = xrif_set_size(
m_xrif_timing, 5, 1, 1, nFrames, XRIF_TYPECODE_UINT64);
1496 if (rv != XRIF_NOERROR)
1499 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif set size error. DATA POSSIBLY LOST."});
1503 if (rv != XRIF_NOERROR)
1506 log<software_error>({__FILE__, __LINE__, 0, rv,
"xrif set LZ4 acceleration error."});
1510 for (
size_t nF = 0; nF < nFrames; ++nF)
1518 rv = xrif_encode(
m_xrif);
1519 if (rv != XRIF_NOERROR)
1522 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif encode error. DATA POSSIBLY LOST."});
1526 if (rv != XRIF_NOERROR)
1529 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif write header error. DATA POSSIBLY LOST."});
1533 if (rv != XRIF_NOERROR)
1536 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif encode error. DATA POSSIBLY LOST."});
1540 if (rv != XRIF_NOERROR)
1543 log<software_alert>({__FILE__, __LINE__, 0, rv,
"xrif write header error. DATA POSSIBLY LOST"});
1550 if (gmtime_r(&fts->tv_sec, &uttime) == 0)
1553 log<software_alert>({__FILE__, __LINE__, errno, 0,
"gmtime_r error. possible loss of timing information."});
1558 uttime.tm_mon + 1, uttime.tm_mday, uttime.tm_hour, uttime.tm_min, uttime.tm_sec,
static_cast<int>(fts->tv_nsec));
1560 if (rv !=
sizeof(
"YYYYMMDDHHMMSSNNNNNNNNN") - 1)
1563 log<software_alert>({__FILE__, __LINE__, errno, rv,
"did not write enough chars to timestamp"});
1569 FILE *fp_xrif = fopen(
m_fname,
"wb");
1570 if (fp_xrif == NULL)
1573 log<software_alert>({__FILE__, __LINE__, errno, 0,
"failed to open file for writing"});
1581 size_t bw = fwrite(
m_xrif_header,
sizeof(uint8_t), XRIF_HEADER_SIZE, fp_xrif);
1583 if (bw != XRIF_HEADER_SIZE)
1585 log<software_alert>({__FILE__, __LINE__, errno, 0,
"failure writing header to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1589 bw = fwrite(
m_xrif->raw_buffer,
sizeof(uint8_t),
m_xrif->compressed_size, fp_xrif);
1591 if (bw !=
m_xrif->compressed_size)
1593 log<software_alert>({__FILE__, __LINE__, errno, 0,
"failure writing data to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1598 if (bw != XRIF_HEADER_SIZE)
1600 log<software_alert>({__FILE__, __LINE__, errno, 0,
"failure writing timing header to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1607 log<software_alert>({__FILE__, __LINE__, errno, 0,
"failure writing timing data to file. DATA LOSS LIKELY. bytes = " + std::to_string(bw)});
1617 log<saving_stop>({0, saveStopFrameNo});
1627 (
const pcf::IndiProperty &
ipRecv)
1641 if (
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On && m_writing ==
NOT_WRITING)
1695 static int16_t lastState = -1;
1696 static uint64_t currSaveStart = -1;
1717 static uint32_t last_rawSize = -1;
1718 static uint32_t last_compressedSize = -1;
1719 static float last_encodeRate = -1;
1720 static float last_differenceRate = -1;
1721 static float last_reorderRate = -1;
1722 static float last_compressRate = -1;
1724 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 ||
1725 m_xrif->reorder_rate != last_reorderRate ||
m_xrif->compress_rate != last_compressRate || force)
1727 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});
1729 last_rawSize =
m_xrif->raw_size;
1730 last_compressedSize =
m_xrif->compressed_size;
1731 last_encodeRate =
m_xrif->encode_rate;
1732 last_differenceRate =
m_xrif->difference_rate;
1733 last_reorderRate =
m_xrif->reorder_rate;
1734 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.
pcf::IndiProperty m_indiP_xrifStats
pcf::IndiProperty m_indiP_writing
double m_currImageTime
The write-time of the current image.
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.
unsigned m_semWaitSec
The time in whole sec to wait on the semaphore, to which m_semWaitNSec is added. Default is 0 nsec.
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)
double m_currChunkStartTime
The write-time of the first image in the chunk.
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.
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.
unsigned m_semWaitNSec
The time in nsec to wait on the semaphore, added to m_semWaitSec. Max is 999999999....
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_currChunkStart
The circular buffer starting position of the current to-be-written chunk.
pid_t m_swThreadID
S.w. thread pid.
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.
double m_maxChunkTime
The maximum time before writing regardless of number of frames.
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.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & 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.
#define XWC_SEM_WAIT_TS_RETVOID(ts, sec, nsec)
Add the wait time to a timespec for a sem_timedwait call, with no value returned on error.
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.
Software CRITICAL log entry.