start development branch.

rewrite image buffer managment (dynamic ring buffer, allocation of
buffers at initialization of camera, no allocation of image buffer per
acquisition process)
This commit is contained in:
Timur A. Fatkhullin 2024-12-27 18:41:46 +03:00
parent 99e072be78
commit c1b7d249da
4 changed files with 146 additions and 114 deletions

View File

@ -44,7 +44,7 @@ RaptorEagleCCD::AcquisitionProcess::AcquisitionProcess(RaptorEagleCCD* manager)
{ {
std::stringstream st; std::stringstream st;
st << std::this_thread::get_id(); st << std::this_thread::get_id();
_manager->logDebug("Create acquisition process (thread id: {})", st.str()); serverPtr->logDebug("Create acquisition process (thread id: {})", st.str());
} }
@ -52,7 +52,7 @@ RaptorEagleCCD::AcquisitionProcess::~AcquisitionProcess()
{ {
std::stringstream st; std::stringstream st;
st << std::this_thread::get_id(); st << std::this_thread::get_id();
_manager->logDebug("Delete acquisition process (thread id: {})", st.str()); serverPtr->logDebug("Delete acquisition process (thread id: {})", st.str());
} }
@ -77,30 +77,30 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
std::stringstream st; std::stringstream st;
st << std::this_thread::get_id(); st << std::this_thread::get_id();
_manager->logDebug("Arm grabber and wait for acquisition starting trigger (thread id: {}) ...", st.str()); serverPtr->logDebug("Arm grabber and wait for acquisition starting trigger (thread id: {}) ...", st.str());
_manager->xclibApiCall(pxd_doSnap(_manager->_cameraUnitmap, 1, timeout.count()), serverPtr->xclibApiCall(pxd_doSnap(serverPtr->_cameraUnitmap, 1, timeout.count()),
std::format("pxd_doSnap({}, 1, {})", _manager->_cameraUnitmap, timeout.count())); std::format("pxd_doSnap({}, 1, {})", serverPtr->_cameraUnitmap, timeout.count()));
_manager->logDebug("Capture is finished (thread id: {})!", st.str()); serverPtr->logDebug("Capture is finished (thread id: {})!", st.str());
if ((_acqParams->abortTime > _acqParams->startTime) && if ((_acqParams->abortTime > _acqParams->startTime) &&
!_acqParams->saveInAbort) { // abort acquisition was occured! just exit !_acqParams->saveInAbort) { // abort acquisition was occured! just exit
_manager->logInfo("It seems the acquisition was aborted! Do not save acquired image!"); serverPtr->logInfo("It seems the acquisition was aborted! Do not save acquired image!");
isAcqInProgress = false; isAcqInProgress = false;
_status = STATUS_IDLE; _status = STATUS_IDLE;
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()); // _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end());
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; // serverPtr->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
return; return;
} }
_manager->logDebug("Image ROI [{}, {}, {}, {}] (binned {}x{})", _acqParams->roiStartX, _acqParams->roiStartY, serverPtr->logDebug("Image ROI [{}, {}, {}, {}] (binned {}x{})", _acqParams->roiStartX, _acqParams->roiStartY,
_acqParams->roiWidth, _acqParams->roiHeight, _acqParams->binX, _acqParams->binY); _acqParams->roiWidth, _acqParams->roiHeight, _acqParams->binX, _acqParams->binY);
_manager->logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str()); serverPtr->logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str());
// compute image dimension // compute image dimension
// NOTE: _acqParams->roiWidth and _acqParams->roiHeight are expected in CCD pixels (not binned)!!! // NOTE: _acqParams->roiWidth and _acqParams->roiHeight are expected in CCD pixels (not binned)!!!
@ -116,62 +116,43 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
LONGLONG npix = dimx * dimy; LONGLONG npix = dimx * dimy;
// NOTE: // NOTE:
auto ldiv = std::lldiv(npix, _manager->_dimCCD[0]); auto ldiv = std::lldiv(npix, serverPtr->_dimCCD[0]);
_imageBufferRows = ldiv.quot + (ldiv.rem ? 1 : 0); _imageBufferRows = ldiv.quot + (ldiv.rem ? 1 : 0);
bool gap = false; bool gap = false;
if ((_acqParams->roiWidth + _acqParams->roiStartX) < _manager->_dimCCD[0]) { if ((_acqParams->roiWidth + _acqParams->roiStartX) < serverPtr->_dimCCD[0]) {
/* IT SEEMS IF MAX ROI X-COORDINATE IS LESS THAN CCD DIM /* IT SEEMS IF MAX ROI X-COORDINATE IS LESS THAN CCD DIM
* EAGLE CAMERA CONTROLLER SETUP READING FOR WIDTH+1 ROI!!! */ * EAGLE CAMERA CONTROLLER SETUP READING FOR WIDTH+1 ROI!!! */
gap = true; gap = true;
++_imageBufferRows; ++_imageBufferRows;
} }
// _imageBufferRows = static_cast<size_t>(std::ceil(npix / _manager->_dimCCD[0])); // _imageBufferRows = static_cast<size_t>(std::ceil(npix / serverPtr->_dimCCD[0]));
// read size // read size
size_t sz = _imageBufferRows * _manager->_dimCCD[0]; // size_t sz = _imageBufferRows * serverPtr->_dimCCD[0];
_imageBufferSize = _imageBufferRows * serverPtr->_dimCCD[0];
try { auto log_str = std::format("pxd_readushort({}, 1, 0, 0, -1, {}, {}, {}, \"{}\")", serverPtr->_cameraUnitmap,
// sz = _manager->_dimCCD[0] * _manager->_dimCCD[1]; _imageBufferRows, (void*)_acqParams->imageBufferPtr, _imageBufferSize, color_space);
if (_imageBufferSize < sz) {
_manager->logDebug("Reallocate image buffer to {} elements", sz);
_imageBufferSize = sz;
_imageBuffer.reset(new ushort[sz]); // may thow std::bad_alloc here!
}
auto log_str = std::format("pxd_readushort({}, 1, 0, 0, -1, {}, {}, {}, \"{}\")", _manager->_cameraUnitmap, serverPtr->xclibApiCall(pxd_readushort(serverPtr->_cameraUnitmap, 1, 0, 0, -1, _imageBufferRows,
_imageBufferRows, (void*)_imageBuffer.get(), _imageBufferSize, color_space); _acqParams->imageBufferPtr, _imageBufferSize, (char*)color_space),
log_str);
// _manager->xclibApiCall(pxd_readushort(_manager->_cameraUnitmap, 1, 0, 0, -1, -1,
// (ushort*)_imageBuffer.get(), _imageBufferSize, (char*)color_space),
// log_str);
_manager->xclibApiCall(pxd_readushort(_manager->_cameraUnitmap, 1, 0, 0, -1, _imageBufferRows,
(ushort*)_imageBuffer.get(), _imageBufferSize, (char*)color_space),
log_str);
isAcqInProgress = false; isAcqInProgress = false;
} catch (...) {
isAcqInProgress = false;
_status = STATUS_IDLE;
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end());
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
throw;
}
// ------- save to FITS file -------- // ------- save to FITS file --------
if (_acqParams->filename.empty()) { if (_acqParams->filename.empty()) {
_manager->logWarn("An empty FITS filename is given! Do not save acquired image!"); serverPtr->logWarn("An empty FITS filename is given! Do not save acquired image!");
_status = STATUS_IDLE; _status = STATUS_IDLE;
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()); // _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end());
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; // serverPtr->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
return; return;
} }
@ -180,13 +161,13 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()) + // _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()) +
// std::format(" {}", _acqParams->filename); // std::format(" {}", _acqParams->filename);
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_SAVE; // serverPtr->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_SAVE;
std::string fname{"!"}; // to overwrite existing file std::string fname{"!"}; // to overwrite existing file
fname += _acqParams->filename; fname += _acqParams->filename;
_manager->logInfo("Try to save FITS file with name '{}'", _acqParams->filename); serverPtr->logInfo("Try to save FITS file with name '{}'", _acqParams->filename);
_manager->logTrace("Actual saving filename: {}", fname); serverPtr->logTrace("Actual saving filename: {}", fname);
fitsfile* fitsFilePtr; fitsfile* fitsFilePtr;
int status = 0; int status = 0;
@ -201,13 +182,13 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
fits_clear_errmsg(); fits_clear_errmsg();
_manager->logDebug("Create an empty FITS file ..."); serverPtr->logDebug("Create an empty FITS file ...");
fits_create_file(&fitsFilePtr, fname.c_str(), &status); fits_create_file(&fitsFilePtr, fname.c_str(), &status);
_manager->logDebug("Create primary FITS HDU (dim = [{}, {}])", naxes[0], naxes[1]); serverPtr->logDebug("Create primary FITS HDU (dim = [{}, {}])", naxes[0], naxes[1]);
fits_create_img(fitsFilePtr, USHORT_IMG, 2, naxes, &status); fits_create_img(fitsFilePtr, USHORT_IMG, 2, naxes, &status);
_manager->logDebug("Write {} pixels to the HDU ...", npix); serverPtr->logDebug("Write {} pixels to the HDU ...", npix);
if (gap) { if (gap) {
/* IT SEEMS IF MAX ROI X-COORDINATE IS LESS THAN CCD DIM /* IT SEEMS IF MAX ROI X-COORDINATE IS LESS THAN CCD DIM
* EAGLE CAMERA CONTROLLER SETUP READING FOR WIDTH+1 ROI!!! * EAGLE CAMERA CONTROLLER SETUP READING FOR WIDTH+1 ROI!!!
@ -259,9 +240,9 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
if (_acqParams->startTime < _acqParams->abortTime) { // acquisition was aborted if (_acqParams->startTime < _acqParams->abortTime) { // acquisition was aborted
std::chrono::duration<double> real_exp = _acqParams->abortTime - _acqParams->startTime; std::chrono::duration<double> real_exp = _acqParams->abortTime - _acqParams->startTime;
_manager->logTrace("Acq. start time: {}; acq. abort time: {}", _acqParams->startTime, serverPtr->logTrace("Acq. start time: {}; acq. abort time: {}", _acqParams->startTime,
_acqParams->abortTime); _acqParams->abortTime);
_manager->logDebug("Exposure was stopped! Recompute the exposure duration to {} secs", real_exp.count()); serverPtr->logDebug("Exposure was stopped! Recompute the exposure duration to {} secs", real_exp.count());
_acqParams->expTime = real_exp.count(); _acqParams->expTime = real_exp.count();
} }
@ -313,11 +294,11 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
if (!status) { if (!status) {
// keywords from user template file // keywords from user template file
if (_acqParams->templateFilename.size() && !status) { if (_acqParams->templateFilename.size() && !status) {
_manager->logDebug("Copy keywords from '{}' template file", _acqParams->templateFilename); serverPtr->logDebug("Copy keywords from '{}' template file", _acqParams->templateFilename);
fits_write_key_template(fitsFilePtr, _acqParams->templateFilename.c_str(), &status); fits_write_key_template(fitsFilePtr, _acqParams->templateFilename.c_str(), &status);
if (status) { // ignore possible errors if (status) { // ignore possible errors
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
_manager->logWarn( serverPtr->logWarn(
"An error occured while copy keywords from the template file '{}' (err = {}, msg = {})! " "An error occured while copy keywords from the template file '{}' (err = {}, msg = {})! "
"Ignore!", "Ignore!",
_acqParams->templateFilename, status, err_str); _acqParams->templateFilename, status, err_str);
@ -332,15 +313,15 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
int k_type; int k_type;
if (_acqParams->permanentKeywords.size()) { if (_acqParams->permanentKeywords.size()) {
_manager->logDebug("Copy {} permanent keywords", _acqParams->permanentKeywords.size()); serverPtr->logDebug("Copy {} permanent keywords", _acqParams->permanentKeywords.size());
} else { } else {
_manager->logDebug("There is no one permanent keyword! Skip!"); serverPtr->logDebug("There is no one permanent keyword! Skip!");
} }
for (auto& s : _acqParams->permanentKeywords) { for (auto& s : _acqParams->permanentKeywords) {
fits_parse_template(s.data(), card, &k_type, &status); fits_parse_template(s.data(), card, &k_type, &status);
if (status) { // ignore possible errors if (status) { // ignore possible errors
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
_manager->logWarn( serverPtr->logWarn(
"An error occured while writing permanent keyword card [{}] (err = {}, msg = {})! " "An error occured while writing permanent keyword card [{}] (err = {}, msg = {})! "
"Ignore!", "Ignore!",
s, status, err_str); s, status, err_str);
@ -352,32 +333,32 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
} }
} }
_manager->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname); serverPtr->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname);
fits_update_card(fitsFilePtr, kname, card, &status); fits_update_card(fitsFilePtr, kname, card, &status);
if (status) { if (status) {
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
_manager->logWarn( serverPtr->logWarn(
"An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname, "An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname,
status, err_str); status, err_str);
} else { } else {
_manager->logTrace("The FITS card (name = '{}') was updated successfully", kname); serverPtr->logTrace("The FITS card (name = '{}') was updated successfully", kname);
} }
} }
// keyword from user (may update template file and permanent keywords!) // keyword from user (may update template file and permanent keywords!)
if (_acqParams->currentKeywords.size()) { if (_acqParams->currentKeywords.size()) {
_manager->logDebug("Copy {} current keywords", _acqParams->currentKeywords.size()); serverPtr->logDebug("Copy {} current keywords", _acqParams->currentKeywords.size());
} else { } else {
_manager->logDebug("There is no one current keyword! Skip!"); serverPtr->logDebug("There is no one current keyword! Skip!");
} }
for (auto& s : _acqParams->currentKeywords) { for (auto& s : _acqParams->currentKeywords) {
fits_parse_template(s.data(), card, &k_type, &status); fits_parse_template(s.data(), card, &k_type, &status);
if (status) { // ignore possible errors if (status) { // ignore possible errors
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
_manager->logWarn( serverPtr->logWarn(
"An error occured while writing user keyword card [{}] (err = {}, msg = {})! " "An error occured while writing user keyword card [{}] (err = {}, msg = {})! "
"Ignore!", "Ignore!",
s, status, err_str); s, status, err_str);
@ -389,54 +370,57 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
} }
} }
_manager->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname); serverPtr->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname);
fits_update_card(fitsFilePtr, kname, card, &status); fits_update_card(fitsFilePtr, kname, card, &status);
if (status) { if (status) {
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
_manager->logWarn( serverPtr->logWarn(
"An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname, "An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname,
status, err_str); status, err_str);
} else { } else {
_manager->logTrace("The FITS card (name = '{}') was updated successfully", kname); serverPtr->logTrace("The FITS card (name = '{}') was updated successfully", kname);
} }
} }
} }
// hardcoded camera hardware version info keywords // hardcoded camera hardware version info keywords
fits_update_key_ulng(fitsFilePtr, "SERNUM", (ULONGLONG)_manager->_cameraSerialNumber, "Camera serial number", fits_update_key_ulng(fitsFilePtr, "SERNUM", (ULONGLONG)serverPtr->_cameraSerialNumber, "Camera serial number",
&status); &status);
str = std::format("{}.{}", _manager->_microVersion[0], _manager->_microVersion[1]); str = std::format("{}.{}", serverPtr->_microVersion[0], serverPtr->_microVersion[1]);
fits_update_key_str(fitsFilePtr, "MICROVER", str.c_str(), "Camera microcontroller version", &status); fits_update_key_str(fitsFilePtr, "MICROVER", str.c_str(), "Camera microcontroller version", &status);
str = std::format("{}.{}", _manager->_FPGAVersion[0], _manager->_FPGAVersion[1]); str = std::format("{}.{}", serverPtr->_FPGAVersion[0], serverPtr->_FPGAVersion[1]);
fits_update_key_str(fitsFilePtr, "FPGAVER", str.c_str(), "Camera FPGA version", &status); fits_update_key_str(fitsFilePtr, "FPGAVER", str.c_str(), "Camera FPGA version", &status);
str = std::format("{}", _manager->_buildDate); str = std::format("{}", serverPtr->_buildDate);
fits_update_key_str(fitsFilePtr, "BUILDDAT", str.c_str(), "Camera build date, YY-MM-DD", &status); fits_update_key_str(fitsFilePtr, "BUILDDAT", str.c_str(), "Camera build date, YY-MM-DD", &status);
fits_update_key_str(fitsFilePtr, "BUILDCOD", sv2cstr(_manager->_buildCode), "Camera build code", &status); fits_update_key_str(fitsFilePtr, "BUILDCOD", sv2cstr(serverPtr->_buildCode), "Camera build code", &status);
fits_close_file(fitsFilePtr, &status); fits_close_file(fitsFilePtr, &status);
_status = STATUS_IDLE; _status = STATUS_IDLE;
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()); // _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end());
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; // serverPtr->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
fits_get_errstatus(status, err_str); fits_get_errstatus(status, err_str);
if (status) { if (status) {
_manager->logError("An error occured while writing FITS file '{}'! FITS status = {} ({})", serverPtr->logError("An error occured while writing FITS file '{}'! FITS status = {} ({})",
_acqParams->filename, status, err_str); _acqParams->filename, status, err_str);
} else { } else {
_manager->logInfo("FITS file '{}' is saved", _acqParams->filename); serverPtr->logInfo("FITS file '{}' is saved", _acqParams->filename);
} }
_imageBuffer.release(); // _imageBuffer.release();
std::lock_guard lock_guard(serverPtr->_acqProcessesMutex);
serverPtr->_acqRingFreeBufferPtrs.push(_acqParams->imageBufferPtr); // return buffer pointer to queue of free
}); });
} }
@ -444,19 +428,19 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
void RaptorEagleCCD::AcquisitionProcess::stop(bool save) void RaptorEagleCCD::AcquisitionProcess::stop(bool save)
{ {
if (isAcqInProgress) { if (isAcqInProgress) {
_manager->logInfo("Abort current acquisition process!"); serverPtr->logInfo("Abort current acquisition process!");
_acqParams->saveInAbort = save; _acqParams->saveInAbort = save;
auto bytes = _manager->readRegisters({0xD4}); // curent trigger mode register auto bytes = serverPtr->readRegisters({0xD4}); // curent trigger mode register
bytes[0] |= CL_ABORT_CURRENT_EXP; // set abort acquisition bit bytes[0] |= CL_ABORT_CURRENT_EXP; // set abort acquisition bit
_acqParams->abortTime = std::chrono::utc_clock::now(); _acqParams->abortTime = std::chrono::utc_clock::now();
_manager->writeRegisters({0xD4}, bytes); serverPtr->writeRegisters({0xD4}, bytes);
} else { } else {
_manager->logWarn("There was no active acquisition process! Ignore!"); serverPtr->logWarn("There was no active acquisition process! Ignore!");
} }
} }

View File

@ -163,6 +163,8 @@ RaptorEagleCCD::RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epi
logInfo("Set video format filename: {}", _epixFmtVideoFilename); logInfo("Set video format filename: {}", _epixFmtVideoFilename);
} }
AcquisitionProcess::serverPtr = this;
initAttrComm(); initAttrComm();
openPIXCI(); openPIXCI();
@ -452,6 +454,28 @@ bool RaptorEagleCCD::initCamera(int unitmap)
xclibApiCall(_bitsPerPixel = pxd_imageBdim(), "pxd_imageBdim()"); xclibApiCall(_bitsPerPixel = pxd_imageBdim(), "pxd_imageBdim()");
xclibApiCall(_imageFrameBuffNumber = pxd_imageZdim(), "pxd_imageZdim()"); xclibApiCall(_imageFrameBuffNumber = pxd_imageZdim(), "pxd_imageZdim()");
// memory
if (_acqRingBuffer.empty()) { // the first init. allocate ring buffer
logDebug("Allocate memory for acquisition ring buffer");
_acqRingBuffer.resize(DEFAULT_ACQ_RING_BUFFER_SIZE);
try {
for (auto& uptr : _acqRingBuffer) {
uptr.reset(new ushort[_dimCCD[0] * _dimCCD[1]]); // full CCD frame
_acqRingFreeBufferPtrs.push(uptr.get());
}
} catch (const std::bad_alloc&) {
logError("Cannot allocate memory for ring buffer!");
return false;
}
} else { // re-initialization. just resize ring buffer to initial default size
_acqRingBuffer.resize(DEFAULT_ACQ_RING_BUFFER_SIZE);
_acqRingFreeBufferPtrs = std::queue<ushort*>();
for (auto& uptr : _acqRingBuffer) {
_acqRingFreeBufferPtrs.push(uptr.get());
}
}
logDebug("------- CCD and grabber hardware info -------"); logDebug("------- CCD and grabber hardware info -------");
logDebug("CCD full-frame dimension [{}, {}] pixels", _dimCCD[0], _dimCCD[1]); logDebug("CCD full-frame dimension [{}, {}] pixels", _dimCCD[0], _dimCCD[1]);
logDebug("CCD bits per pixel: {}", _bitsPerPixel); logDebug("CCD bits per pixel: {}", _bitsPerPixel);
@ -965,6 +989,26 @@ void RaptorEagleCCD::startAquisition()
throw std::system_error(RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE); throw std::system_error(RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE);
} }
std::lock_guard lock_guard(_acqProcessesMutex);
if (_acqRingFreeBufferPtrs.empty()) {
logDebug("There is no free image buffers! Try to shrink ring buffer ...");
if (_acqRingBuffer.size() < DEFAULT_ACQ_RING_BUFFER_MAX_SIZE) { // shrink
size_t N = 0;
for (auto i = _acqRingBuffer.size(); i < DEFAULT_ACQ_RING_BUFFER_MAX_SIZE; ++i, ++N) {
if (N == DEFAULT_ACQ_RING_BUFFER_SIZE) {
break;
}
_acqRingBuffer.emplace_back(new ushort[_dimCCD[0] * _dimCCD[1]]);
_acqRingFreeBufferPtrs.push(_acqRingBuffer.back().get());
}
logDebug("{} new image buffers were allocated", N);
} else {
logError("Ring buffer exceeded maximum size!");
throw std::system_error(RaptorEagleCCDError::ERROR_NO_FREE_BUFFER);
}
}
// check filesystem permissions // check filesystem permissions
std::string fname = (*this)[CAMERA_ATTR_FITS_FILENAME]; std::string fname = (*this)[CAMERA_ATTR_FITS_FILENAME];
@ -998,32 +1042,33 @@ void RaptorEagleCCD::startAquisition()
logInfo("Start acquisition process ..."); logInfo("Start acquisition process ...");
auto acq_pars = std::make_shared<acq_params_t>(acq_params_t({ auto acq_pars = std::make_shared<acq_params_t>(
.startTime = std::chrono::utc_clock::time_point(), acq_params_t({.startTime = std::chrono::utc_clock::time_point(),
.abortTime = std::chrono::utc_clock::time_point(), .abortTime = std::chrono::utc_clock::time_point(),
.saveInAbort = false, .saveInAbort = false,
.expTime = (*this)[CAMERA_ATTR_EXPTIME], .expTime = (*this)[CAMERA_ATTR_EXPTIME],
.roiStartX = (*this)[CAMERA_ATTR_ROI_STARTX], // in CCD pixels (start from 0) .roiStartX = (*this)[CAMERA_ATTR_ROI_STARTX], // in CCD pixels (start from 0)
.roiStartY = (*this)[CAMERA_ATTR_ROI_STARTY], // in CCD pixels (start from 0) .roiStartY = (*this)[CAMERA_ATTR_ROI_STARTY], // in CCD pixels (start from 0)
.roiWidth = (*this)[CAMERA_ATTR_ROI_WIDTH], // in binned pixels .roiWidth = (*this)[CAMERA_ATTR_ROI_WIDTH], // in binned pixels
.roiHeight = (*this)[CAMERA_ATTR_ROI_HEIGHT], // in binned pixels .roiHeight = (*this)[CAMERA_ATTR_ROI_HEIGHT], // in binned pixels
.binX = (*this)[CAMERA_ATTR_XBIN], .binX = (*this)[CAMERA_ATTR_XBIN],
.binY = (*this)[CAMERA_ATTR_YBIN], .binY = (*this)[CAMERA_ATTR_YBIN],
.shutterState = (*this)[CAMERA_ATTR_SHUTTER_STATE], .shutterState = (*this)[CAMERA_ATTR_SHUTTER_STATE],
.readRate = (*this)[CAMERA_ATTR_READ_RATE], .readRate = (*this)[CAMERA_ATTR_READ_RATE],
.readMode = (*this)[CAMERA_ATTR_READ_MODE], .readMode = (*this)[CAMERA_ATTR_READ_MODE],
.gain = (*this)[CAMERA_ATTR_GAIN], .gain = (*this)[CAMERA_ATTR_GAIN],
.ccdTemp = (*this)[CAMERA_ATTR_CCD_TEMP], .ccdTemp = (*this)[CAMERA_ATTR_CCD_TEMP],
.tecSetPoint = (*this)[CAMERA_ATTR_TECPOINT], .tecSetPoint = (*this)[CAMERA_ATTR_TECPOINT],
.tecState = (*this)[CAMERA_ATTR_TECSTATE] == CAMERA_ATTR_TECSTATE_ON ? true : false, .tecState = (*this)[CAMERA_ATTR_TECSTATE] == CAMERA_ATTR_TECSTATE_ON ? true : false,
.pcbTemp = (*this)[CAMERA_ATTR_PCB_TEMP], .pcbTemp = (*this)[CAMERA_ATTR_PCB_TEMP],
// .filename = (*this)[CAMERA_ATTR_FITS_FILENAME], // .filename = (*this)[CAMERA_ATTR_FITS_FILENAME],
.filename = fname, .filename = fname,
.templateFilename = (*this)[CAMERA_ATTR_FITS_TEMPLATE], .templateFilename = (*this)[CAMERA_ATTR_FITS_TEMPLATE],
.permanentKeywords = _permanentFitsKeywords, // copy .permanentKeywords = _permanentFitsKeywords, // copy
.currentKeywords = std::move(_currentFitsKeywords) // move!!! .currentKeywords = std::move(_currentFitsKeywords), // move!!!
})); .imageBufferPtr = _acqRingFreeBufferPtrs.front()}));
_acqRingFreeBufferPtrs.pop();
// adjust geometry // adjust geometry
@ -1041,7 +1086,7 @@ void RaptorEagleCCD::startAquisition()
} }
std::lock_guard lock_guard(_acqProcessesMutex); // std::lock_guard lock_guard(_acqProcessesMutex);
auto sptr = std::make_shared<AcquisitionProcess>(this); auto sptr = std::make_shared<AcquisitionProcess>(this);
for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) { for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) {
@ -1056,11 +1101,6 @@ void RaptorEagleCCD::startAquisition()
// arm grabber here // arm grabber here
sptr->start(acq_pars); sptr->start(acq_pars);
// bits.set(CL_TRIGGER_MODE_SNAPSHOT_BIT); // start snapshot bit
// bytes[0] = static_cast<uint8_t>(bits.to_ulong());
// acq_pars->startTime = std::chrono::utc_clock::now();
// writeRegisters({0xD4}, bytes); // write to trigger mode register (start snapshot)
// start acquisition here // start acquisition here
acq_pars->startTime = setTriggerRegisterBit(CL_TRIGGER_MODE_SNAPSHOT_BIT); acq_pars->startTime = setTriggerRegisterBit(CL_TRIGGER_MODE_SNAPSHOT_BIT);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <queue>
#ifdef USE_SPDLOG_LIBRARY #ifdef USE_SPDLOG_LIBRARY
#include <spdlog/sinks/null_sink.h> #include <spdlog/sinks/null_sink.h>
#endif #endif
@ -33,6 +34,7 @@ public:
static constexpr std::string_view USER_FITS_KEY_SEP_SEQ{"\t"}; static constexpr std::string_view USER_FITS_KEY_SEP_SEQ{"\t"};
static constexpr size_t DEFAULT_ACQ_RING_BUFFER_SIZE = 3; static constexpr size_t DEFAULT_ACQ_RING_BUFFER_SIZE = 3;
static constexpr size_t DEFAULT_ACQ_RING_BUFFER_MAX_SIZE = 100;
/* some Eagle V camera constants */ /* some Eagle V camera constants */
// static constexpr double EAGLE_CAMERA_MAX_EXPTIME = 27487.7906944; // in seconds (0xFFFFFFFFFF * 25nsec) // static constexpr double EAGLE_CAMERA_MAX_EXPTIME = 27487.7906944; // in seconds (0xFFFFFFFFFF * 25nsec)
@ -197,6 +199,7 @@ private:
// std::unique_ptr<ushort> imageBuffer; // std::unique_ptr<ushort> imageBuffer;
// size_t imageBufferSize; // size_t imageBufferSize;
// size_t imageBufferRows; // size_t imageBufferRows;
ushort* imageBufferPtr;
}; };
class AcquisitionProcess : public std::enable_shared_from_this<AcquisitionProcess> class AcquisitionProcess : public std::enable_shared_from_this<AcquisitionProcess>
@ -212,6 +215,8 @@ private:
std::string status(); std::string status();
private: private:
inline static RaptorEagleCCD* serverPtr = nullptr;
inline static std::atomic_bool isAcqInProgress = false; inline static std::atomic_bool isAcqInProgress = false;
RaptorEagleCCD* _manager; RaptorEagleCCD* _manager;
@ -257,8 +262,8 @@ private:
std::vector<std::string> _currentFitsKeywords{}; // current acquisition FITS keywords std::vector<std::string> _currentFitsKeywords{}; // current acquisition FITS keywords
std::vector<std::string> _permanentFitsKeywords{}; // permanent user FITS keywords std::vector<std::string> _permanentFitsKeywords{}; // permanent user FITS keywords
// std::list<std::unique_ptr<ushort>> _acqRingBuffer; std::vector<std::unique_ptr<ushort[]>> _acqRingBuffer{};
std::list<std::pair<std::unique_ptr<ushort>, size_t>> _acqRingBuffer; std::queue<ushort*> _acqRingFreeBufferPtrs{};
// hardware version info // hardware version info

View File

@ -17,7 +17,8 @@ enum class RaptorEagleCCDError : int {
ERROR_EXT_TRIGGER_MODE, ERROR_EXT_TRIGGER_MODE,
ERROR_ACQUISITION_IN_PROGRESS, ERROR_ACQUISITION_IN_PROGRESS,
ERROR_INVALID_PATH, ERROR_INVALID_PATH,
ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS,
ERROR_NO_FREE_BUFFER
}; };
@ -68,6 +69,8 @@ struct RaptorEagleCCDErrorCategory : std::error_category {
return "invalid filesystem path"; return "invalid filesystem path";
case RaptorEagleCCDError::ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS: case RaptorEagleCCDError::ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS:
return "insufficient filesystem permissions"; return "insufficient filesystem permissions";
case RaptorEagleCCDError::ERROR_NO_FREE_BUFFER:
return "there is no free buffer in ring";
default: default:
return "UNKNOWN ERROR"; return "UNKNOWN ERROR";
} }