Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce29f05ca0 | |||
| a6f15e234f | |||
|
|
7497b72b32 | ||
| cf3e34f88c | |||
| 8c319780dc | |||
|
|
d103ed2887 | ||
| c1b7d249da |
@ -40,11 +40,11 @@ double JulianDay(const std::chrono::utc_clock::time_point& tm)
|
|||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
RaptorEagleCCD::AcquisitionProcess::AcquisitionProcess(RaptorEagleCCD* manager) : _manager(manager)
|
RaptorEagleCCD::AcquisitionProcess::AcquisitionProcess()
|
||||||
{
|
{
|
||||||
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,23 +52,22 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_t>& params)
|
void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_t>& params)
|
||||||
{
|
{
|
||||||
// if (isAcqInProgress) {
|
|
||||||
// throw std::system_error(RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS);
|
|
||||||
// }
|
|
||||||
|
|
||||||
isAcqInProgress = true;
|
isAcqInProgress = true;
|
||||||
|
|
||||||
// _acqParams = std::move(params);
|
|
||||||
_acqParams = params;
|
_acqParams = params;
|
||||||
// _acqParams->abortTime = std::chrono::utc_clock::time_point(); // to ensure the time point is in past
|
|
||||||
|
|
||||||
_snapAndCopyFuture = std::async(std::launch::async, [self = shared_from_this(), this]() {
|
std::thread([self = shared_from_this(), this]() {
|
||||||
|
{
|
||||||
|
std::lock_guard lock_guard(serverPtr->_acqProcessesMutex);
|
||||||
|
acqProcSptr.insert(self);
|
||||||
|
}
|
||||||
|
|
||||||
std::chrono::milliseconds timeout =
|
std::chrono::milliseconds timeout =
|
||||||
CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT +
|
CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT +
|
||||||
std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(_acqParams->expTime * 1000));
|
std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(_acqParams->expTime * 1000));
|
||||||
@ -77,149 +76,116 @@ 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()),
|
_status = STATUS_ARMED; // change to STATUS_ACQ will be made in RaptorEagleCCD::startAcquisition!!!
|
||||||
std::format("pxd_doSnap({}, 1, {})", _manager->_cameraUnitmap, timeout.count()));
|
|
||||||
|
|
||||||
_manager->logDebug("Capture is finished (thread id: {})!", st.str());
|
serverPtr->xclibApiCall(pxd_doSnap(serverPtr->_cameraUnitmap, 1, timeout.count()),
|
||||||
|
std::format("pxd_doSnap({}, 1, {})", serverPtr->_cameraUnitmap, timeout.count()));
|
||||||
|
|
||||||
|
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!");
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
|
serverPtr->logInfo("It seems the acquisition was aborted! Do not save acquired image!");
|
||||||
|
|
||||||
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)!!!
|
||||||
|
|
||||||
// auto div = std::div(_acqParams->roiWidth - _acqParams->roiStartX, _acqParams->binX);
|
|
||||||
auto div = std::div(_acqParams->roiWidth, _acqParams->binX);
|
auto div = std::div(_acqParams->roiWidth, _acqParams->binX);
|
||||||
auto dimx = div.quot + (div.rem ? 1 : 0);
|
auto dimx = div.quot + (div.rem ? 1 : 0);
|
||||||
// div = std::div(_acqParams->roiHeight - _acqParams->roiStartY, _acqParams->binY);
|
|
||||||
div = std::div(_acqParams->roiHeight, _acqParams->binY);
|
div = std::div(_acqParams->roiHeight, _acqParams->binY);
|
||||||
auto dimy = div.quot + (div.rem ? 1 : 0);
|
auto dimy = div.quot + (div.rem ? 1 : 0);
|
||||||
|
|
||||||
// LONGLONG npix = _acqParams->roiWidth * _acqParams->roiHeight;
|
|
||||||
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);
|
auto im_buffer_rows = 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;
|
++im_buffer_rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _imageBufferRows = static_cast<size_t>(std::ceil(npix / _manager->_dimCCD[0]));
|
|
||||||
|
|
||||||
// read size
|
// read size
|
||||||
size_t sz = _imageBufferRows * _manager->_dimCCD[0];
|
auto im_buffer_size = im_buffer_rows * serverPtr->_dimCCD[0];
|
||||||
|
|
||||||
try {
|
auto log_str = std::format("pxd_readushort({}, 1, 0, 0, -1, {}, {}, {}, \"{}\")", serverPtr->_cameraUnitmap,
|
||||||
// sz = _manager->_dimCCD[0] * _manager->_dimCCD[1];
|
im_buffer_rows, (void*)_acqParams->imageBufferPtr, im_buffer_size, 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, im_buffer_rows,
|
||||||
_imageBufferRows, (void*)_imageBuffer.get(), _imageBufferSize, color_space);
|
_acqParams->imageBufferPtr, im_buffer_size, (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());
|
|
||||||
|
|
||||||
// _manager->_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_status = STATUS_SAVE;
|
_status = STATUS_SAVE;
|
||||||
// _status = std::string(CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()) +
|
|
||||||
// std::format(" {}", _acqParams->filename);
|
|
||||||
|
|
||||||
// _manager->_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;
|
||||||
|
|
||||||
const int naxis = 2;
|
const int naxis = 2;
|
||||||
long naxes[naxis] = {dimx, dimy};
|
long naxes[naxis] = {dimx, dimy};
|
||||||
// long naxes[2];
|
|
||||||
// naxes[0] = _acqParams->roiWidth;
|
|
||||||
// naxes[1] = _acqParams->roiHeight;
|
|
||||||
|
|
||||||
char err_str[100];
|
char err_str[100];
|
||||||
|
|
||||||
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!!!
|
||||||
* SO ONE NEEDS TO WRITE IMAGE PER ROW WITH SKIPPING EXTRA PIXEL
|
* SO ONE NEEDS TO WRITE IMAGE PER ROW WITH SKIPPING EXTRA PIXEL
|
||||||
* AT THE END OF EACH ROW
|
* AT THE END OF EACH ROW
|
||||||
*/
|
*/
|
||||||
auto ptr = _imageBuffer.get();
|
for (int i = 0; i < dimy; ++i) {
|
||||||
for (size_t i = 0; i < dimy; ++i) {
|
fits_write_img(fitsFilePtr, TUSHORT, i * dimx + 1, dimx, _acqParams->imageBufferPtr, &status);
|
||||||
fits_write_img(fitsFilePtr, TUSHORT, i * dimx + 1, dimx, _imageBuffer.get(), &status);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fits_write_img(fitsFilePtr, TUSHORT, 1, npix, (void*)_imageBuffer.get(), &status);
|
fits_write_img(fitsFilePtr, TUSHORT, 1, npix, _acqParams->imageBufferPtr, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -259,9 +225,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 +279,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);
|
||||||
@ -326,137 +292,116 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// permanent keywords (may update keywords from template file!)
|
|
||||||
char card[81];
|
|
||||||
char kname[9] = " ";
|
|
||||||
int k_type;
|
|
||||||
|
|
||||||
if (_acqParams->permanentKeywords.size()) {
|
auto save_keywords = [&status, &err_str, &fitsFilePtr](auto& kwd_list, const std::string& mark) {
|
||||||
_manager->logDebug("Copy {} permanent keywords", _acqParams->permanentKeywords.size());
|
char card[81];
|
||||||
} else {
|
char kname[9] = " ";
|
||||||
_manager->logDebug("There is no one permanent keyword! Skip!");
|
int k_type;
|
||||||
}
|
|
||||||
for (auto& s : _acqParams->permanentKeywords) {
|
|
||||||
fits_parse_template(s.data(), card, &k_type, &status);
|
|
||||||
if (status) { // ignore possible errors
|
|
||||||
fits_get_errstatus(status, err_str);
|
|
||||||
_manager->logWarn(
|
|
||||||
"An error occured while writing permanent keyword card [{}] (err = {}, msg = {})! "
|
|
||||||
"Ignore!",
|
|
||||||
s, status, err_str);
|
|
||||||
|
|
||||||
status = 0;
|
if (kwd_list.size()) {
|
||||||
|
serverPtr->logDebug("Copy {} {} keywords", mark, kwd_list.size());
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 8; ++i) {
|
serverPtr->logDebug("There is no one permanent keyword! Skip!");
|
||||||
kname[i] = card[i];
|
}
|
||||||
|
for (auto& s : kwd_list) {
|
||||||
|
fits_parse_template(s.data(), card, &k_type, &status);
|
||||||
|
if (status) { // ignore possible errors
|
||||||
|
fits_get_errstatus(status, err_str);
|
||||||
|
serverPtr->logWarn(
|
||||||
|
"An error occured while writing {} keyword card [{}] (err = {}, msg = {})! "
|
||||||
|
"Ignore!",
|
||||||
|
mark, s, status, err_str);
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
kname[i] = card[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverPtr->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname);
|
||||||
|
|
||||||
|
fits_update_card(fitsFilePtr, kname, card, &status);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
fits_get_errstatus(status, err_str);
|
||||||
|
serverPtr->logWarn(
|
||||||
|
"An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!",
|
||||||
|
kname, status, err_str);
|
||||||
|
} else {
|
||||||
|
serverPtr->logTrace("The FITS card (name = '{}') was updated successfully", kname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
_manager->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname);
|
// permanent keywords (may update keywords from template file!)
|
||||||
|
save_keywords(_acqParams->permanentKeywords, "permanent");
|
||||||
fits_update_card(fitsFilePtr, kname, card, &status);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
fits_get_errstatus(status, err_str);
|
|
||||||
_manager->logWarn(
|
|
||||||
"An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname,
|
|
||||||
status, err_str);
|
|
||||||
} else {
|
|
||||||
_manager->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()) {
|
save_keywords(_acqParams->currentKeywords, "current");
|
||||||
_manager->logDebug("Copy {} current keywords", _acqParams->currentKeywords.size());
|
|
||||||
} else {
|
|
||||||
_manager->logDebug("There is no one current keyword! Skip!");
|
|
||||||
}
|
|
||||||
for (auto& s : _acqParams->currentKeywords) {
|
|
||||||
fits_parse_template(s.data(), card, &k_type, &status);
|
|
||||||
if (status) { // ignore possible errors
|
|
||||||
fits_get_errstatus(status, err_str);
|
|
||||||
_manager->logWarn(
|
|
||||||
"An error occured while writing user keyword card [{}] (err = {}, msg = {})! "
|
|
||||||
"Ignore!",
|
|
||||||
s, status, err_str);
|
|
||||||
|
|
||||||
status = 0;
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
kname[i] = card[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_manager->logTrace("Try to update [{}] FITS card (name = '{}')", card, kname);
|
|
||||||
|
|
||||||
fits_update_card(fitsFilePtr, kname, card, &status);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
fits_get_errstatus(status, err_str);
|
|
||||||
_manager->logWarn(
|
|
||||||
"An error occured while updating FITS card (name = '{}') (err = {}, msg = {})! Skip!", kname,
|
|
||||||
status, err_str);
|
|
||||||
} else {
|
|
||||||
_manager->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());
|
|
||||||
// _manager->_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();
|
|
||||||
});
|
std::lock_guard lock_guard(serverPtr->_acqProcessesMutex);
|
||||||
|
|
||||||
|
serverPtr->_acqRingFreeBufferPtrs.push(_acqParams->imageBufferPtr); // return buffer pointer to queue of free
|
||||||
|
|
||||||
|
serverPtr->logDebug("Return buffer address {} to queue of free", (void*)_acqParams->imageBufferPtr);
|
||||||
|
|
||||||
|
acqProcSptr.erase(self);
|
||||||
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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}); // current 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);
|
||||||
|
|
||||||
|
_acqParams->abortTime = serverPtr->setTriggerRegisterBit(CL_TRIGGER_MODE_ABORT_CURRENT_EXP_BIT);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_manager->logWarn("There was no active acquisition process! Ignore!");
|
serverPtr->logWarn("There was no active acquisition process! Ignore!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,30 +410,35 @@ std::string RaptorEagleCCD::AcquisitionProcess::status()
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(_statusMutex);
|
std::lock_guard lock(_statusMutex);
|
||||||
|
|
||||||
|
std::string stat_str;
|
||||||
|
|
||||||
switch (_status) {
|
switch (_status) {
|
||||||
case STATUS_IDLE:
|
case STATUS_IDLE:
|
||||||
_statusString = std::format("{}", CAMERA_ATTR_CAMERA_STATUS_IDLE);
|
stat_str = std::format("{}", CAMERA_ATTR_CAMERA_STATUS_IDLE);
|
||||||
|
break;
|
||||||
|
case STATUS_ARMED: // actually it should not be! but it presents here for debug reasons
|
||||||
|
stat_str = std::format("{}", CAMERA_ATTR_CAMERA_STATUS_ARMED);
|
||||||
break;
|
break;
|
||||||
case STATUS_ACQ: {
|
case STATUS_ACQ: {
|
||||||
std::chrono::duration<double> curr_exp = std::chrono::utc_clock::now() - _acqParams->startTime;
|
std::chrono::duration<double> curr_exp = std::chrono::utc_clock::now() - _acqParams->startTime;
|
||||||
auto remain_exp = _acqParams->expTime - curr_exp.count();
|
auto remain_exp = _acqParams->expTime - curr_exp.count();
|
||||||
if (remain_exp < 0) {
|
if (remain_exp < 0) {
|
||||||
_status = STATUS_READ;
|
_status = STATUS_READ;
|
||||||
_statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename);
|
stat_str = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename);
|
||||||
} else {
|
} else {
|
||||||
_statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_ACQ, remain_exp);
|
stat_str = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_ACQ, remain_exp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case STATUS_READ:
|
case STATUS_READ:
|
||||||
_statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename);
|
stat_str = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename);
|
||||||
break;
|
break;
|
||||||
case STATUS_SAVE:
|
case STATUS_SAVE:
|
||||||
_statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_SAVE, _acqParams->filename);
|
stat_str = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_SAVE, _acqParams->filename);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_statusString = "UNKNOWN"; // is should not be!!!
|
stat_str = "UNKNOWN"; // is should not be!!!
|
||||||
}
|
}
|
||||||
|
|
||||||
return _statusString;
|
return stat_str;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
@ -177,8 +179,28 @@ RaptorEagleCCD::RaptorEagleCCD(std::shared_ptr<spdlog::logger> logger)
|
|||||||
|
|
||||||
RaptorEagleCCD::~RaptorEagleCCD()
|
RaptorEagleCCD::~RaptorEagleCCD()
|
||||||
{
|
{
|
||||||
|
if (AcquisitionProcess::isAcqInProgress) {
|
||||||
|
(*this)[CAMERA_CMD_ABORT_EXP];
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for detached acquisition threads?
|
||||||
|
if (AcquisitionProcess::acqProcSptr.size()) {
|
||||||
|
logInfo("DTOR: waiting for the end of the acquisition process {} ...",
|
||||||
|
AcquisitionProcess::acqProcSptr.size() > 1 ? "threads" : "thread");
|
||||||
|
|
||||||
|
auto start = std::chrono::utc_clock::now();
|
||||||
|
while (AcquisitionProcess::acqProcSptr.size()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
|
||||||
|
if ((std::chrono::utc_clock::now() - start) >= std::chrono::milliseconds(2000)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
closePIXCI();
|
closePIXCI();
|
||||||
|
|
||||||
|
|
||||||
logDebug("DTOR: Delete RaptorEagleCCD class instance");
|
logDebug("DTOR: Delete RaptorEagleCCD class instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,6 +474,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 +1009,28 @@ void RaptorEagleCCD::startAquisition()
|
|||||||
throw std::system_error(RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE);
|
throw std::system_error(RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_acqRingFreeBufferPtrs.empty()) {
|
||||||
|
logDebug("There is no free image buffers! Try to shrink ring buffer ...");
|
||||||
|
|
||||||
|
std::lock_guard lock_guard(_acqProcessesMutex);
|
||||||
|
|
||||||
|
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 +1064,35 @@ 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()}));
|
||||||
|
|
||||||
|
logDebug("Current acquisition buffer address: {}", (void*)_acqRingFreeBufferPtrs.front());
|
||||||
|
|
||||||
|
_acqRingFreeBufferPtrs.pop();
|
||||||
|
|
||||||
|
|
||||||
// adjust geometry
|
// adjust geometry
|
||||||
@ -1041,37 +1110,25 @@ void RaptorEagleCCD::startAquisition()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::lock_guard lock_guard(_acqProcessesMutex);
|
auto sptr = std::make_shared<AcquisitionProcess>();
|
||||||
|
sptr->start(acq_pars); // asynchronous call!!!
|
||||||
auto sptr = std::make_shared<AcquisitionProcess>(this);
|
|
||||||
for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) {
|
|
||||||
if (it->expired()) {
|
|
||||||
it = _acqProcesses.erase(it);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_acqProcesses.emplace_back(sptr);
|
|
||||||
// arm grabber here
|
|
||||||
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
|
||||||
|
auto start = std::chrono::utc_clock::now();
|
||||||
|
while (sptr->_status != AcquisitionProcess::STATUS_ARMED) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
if ((std::chrono::utc_clock::now() - start) > CAMERA_START_ACQ_TIMEOUT) {
|
||||||
|
logError("CANNOT START ACQUIRING!!!");
|
||||||
|
throw std::system_error(RaptorEagleCCDError::ERROR_CANNOT_START_ACQUISITION);
|
||||||
|
}
|
||||||
|
}
|
||||||
acq_pars->startTime = setTriggerRegisterBit(CL_TRIGGER_MODE_SNAPSHOT_BIT);
|
acq_pars->startTime = setTriggerRegisterBit(CL_TRIGGER_MODE_SNAPSHOT_BIT);
|
||||||
|
sptr->_status = AcquisitionProcess::STATUS_ACQ;
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
xclibApiCall(status = pxd_goneLive(_cameraUnitmap, 0), std::format("pxd_goneLive({}, 0)", _cameraUnitmap));
|
xclibApiCall(status = pxd_goneLive(_cameraUnitmap, 0), std::format("pxd_goneLive({}, 0)", _cameraUnitmap));
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
logError("CANNOT START ACQUIRING!!!");
|
logError("CANNOT START ACQUIRING!!!");
|
||||||
sptr->_status = AcquisitionProcess::STATUS_IDLE;
|
|
||||||
} else {
|
|
||||||
sptr->_status = AcquisitionProcess::STATUS_ACQ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1080,13 +1137,10 @@ void RaptorEagleCCD::stopAcquisition(bool save_acq)
|
|||||||
{
|
{
|
||||||
std::lock_guard lock_guard(_acqProcessesMutex);
|
std::lock_guard lock_guard(_acqProcessesMutex);
|
||||||
|
|
||||||
for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) {
|
for (auto& sptr : AcquisitionProcess::acqProcSptr) {
|
||||||
if (it->expired()) {
|
if (sptr->_status == AcquisitionProcess::STATUS_ACQ) {
|
||||||
it = _acqProcesses.erase(it);
|
|
||||||
} else {
|
|
||||||
auto sptr = it->lock();
|
|
||||||
sptr->stop(save_acq);
|
sptr->stop(save_acq);
|
||||||
return; // there was only the single active aquisition, so exit here!
|
return; // the only one active acquisition process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1222,36 +1276,23 @@ void RaptorEagleCCD::initAttrComm()
|
|||||||
addAttribute(CAMERA_ATTR_CAMERA_STATUS, [this]() {
|
addAttribute(CAMERA_ATTR_CAMERA_STATUS, [this]() {
|
||||||
std::lock_guard lock_guard(_acqProcessesMutex);
|
std::lock_guard lock_guard(_acqProcessesMutex);
|
||||||
|
|
||||||
std::string s, s_head;
|
std::string s;
|
||||||
|
|
||||||
if (!_acqProcesses.empty()) {
|
if (AcquisitionProcess::isAcqInProgress) {
|
||||||
for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) {
|
s = CAMERA_ATTR_CAMERA_STATUS_ACQ;
|
||||||
if (it->expired()) {
|
s += ",";
|
||||||
it = _acqProcesses.erase(it);
|
}
|
||||||
} else {
|
|
||||||
auto sptr = it->lock();
|
if (AcquisitionProcess::acqProcSptr.size()) {
|
||||||
auto st = sptr->status();
|
for (auto& sptr : AcquisitionProcess::acqProcSptr) {
|
||||||
if (st.substr(0, CAMERA_ATTR_CAMERA_STATUS_ACQ.size()) ==
|
if (sptr->_status != AcquisitionProcess::STATUS_ACQ) {
|
||||||
CAMERA_ATTR_CAMERA_STATUS_ACQ) { // if the camera is acquiring then
|
s += sptr->status() + ",";
|
||||||
s_head = st + ","; // return it at the beginning of the status string
|
|
||||||
} else if (st.substr(0, CAMERA_ATTR_CAMERA_STATUS_IDLE.size()) == CAMERA_ATTR_CAMERA_STATUS_IDLE) {
|
|
||||||
// here, cquisition process is already inactive
|
|
||||||
it = _acqProcesses.erase(it);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
std::ranges::copy(st, std::back_inserter(s));
|
|
||||||
s += ",";
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s.empty() || !s_head.empty()) {
|
if (!s.empty()) {
|
||||||
s = s_head + s;
|
|
||||||
// if (_acqProcesses.size() == 1) {
|
|
||||||
s.resize(s.size() - 1); // delete trailing ","
|
s.resize(s.size() - 1); // delete trailing ","
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
s = std::string{CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()};
|
s = std::string{CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()};
|
||||||
}
|
}
|
||||||
@ -1284,11 +1325,13 @@ void RaptorEagleCCD::initAttrComm()
|
|||||||
addAttribute(
|
addAttribute(
|
||||||
CAMERA_ATTR_FITS_TEMPLATE,
|
CAMERA_ATTR_FITS_TEMPLATE,
|
||||||
[this]() {
|
[this]() {
|
||||||
logTrace("Return current FITS-image header template filename as {}", _currentTemplateFile);
|
logTrace("Return current FITS-image header template filename as {}",
|
||||||
|
_currentTemplateFile.size() ? _currentTemplateFile : "<empty string>");
|
||||||
return _currentTemplateFile;
|
return _currentTemplateFile;
|
||||||
},
|
},
|
||||||
[this](const std::string& filename) {
|
[this](const std::string& filename) {
|
||||||
logDebug("Set current FITS-image header template filename to {}", filename);
|
logDebug("Set current FITS-image header template filename to {}",
|
||||||
|
filename.size() ? filename : "<empty string>");
|
||||||
|
|
||||||
_currentTemplateFile = filename;
|
_currentTemplateFile = filename;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
#ifdef USE_SPDLOG_LIBRARY
|
#ifdef USE_SPDLOG_LIBRARY
|
||||||
#include <spdlog/sinks/null_sink.h>
|
#include <spdlog/sinks/null_sink.h>
|
||||||
#endif
|
#endif
|
||||||
@ -33,6 +35,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)
|
||||||
@ -68,6 +71,9 @@ public:
|
|||||||
std::chrono::milliseconds(1000)};
|
std::chrono::milliseconds(1000)};
|
||||||
|
|
||||||
|
|
||||||
|
// wait timeout to start acquisition (deadlock?!!)
|
||||||
|
static constexpr std::chrono::milliseconds CAMERA_START_ACQ_TIMEOUT{1000}; // 1 second
|
||||||
|
|
||||||
// additive constant to timeout for capture process (see pxd_doSnap XCLIB function)
|
// additive constant to timeout for capture process (see pxd_doSnap XCLIB function)
|
||||||
// this constant will be added to exposure to compute actual timeout
|
// this constant will be added to exposure to compute actual timeout
|
||||||
static constexpr std::chrono::milliseconds CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT{240000}; // 4 mins
|
static constexpr std::chrono::milliseconds CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT{240000}; // 4 mins
|
||||||
@ -149,6 +155,7 @@ public:
|
|||||||
|
|
||||||
// camera status
|
// camera status
|
||||||
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_IDLE{"IDLE"};
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_IDLE{"IDLE"};
|
||||||
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_ARMED{"ARMED"};
|
||||||
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_ACQ{"ACQ"}; // camera is acquiring
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_ACQ{"ACQ"}; // camera is acquiring
|
||||||
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_READ{"READING"}; // camera is reading from CCD
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_READ{"READING"}; // camera is reading from CCD
|
||||||
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_SAVE{"SAVING"}; // camera is saving to FITS file
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_SAVE{"SAVING"}; // camera is saving to FITS file
|
||||||
@ -197,6 +204,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>
|
||||||
@ -204,27 +212,24 @@ private:
|
|||||||
friend class RaptorEagleCCD;
|
friend class RaptorEagleCCD;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AcquisitionProcess(RaptorEagleCCD*);
|
AcquisitionProcess();
|
||||||
~AcquisitionProcess();
|
~AcquisitionProcess();
|
||||||
|
|
||||||
void start(const std::shared_ptr<acq_params_t>& params); // asynchronous method!
|
void start(const std::shared_ptr<acq_params_t>& params); // asynchronous method!
|
||||||
void stop(bool save = true);
|
void stop(bool save = true);
|
||||||
std::string status();
|
std::string status();
|
||||||
|
|
||||||
|
// static std::string acqProcStatus();
|
||||||
private:
|
private:
|
||||||
|
inline static RaptorEagleCCD* serverPtr = nullptr;
|
||||||
|
|
||||||
inline static std::atomic_bool isAcqInProgress = false;
|
inline static std::atomic_bool isAcqInProgress = false;
|
||||||
|
|
||||||
RaptorEagleCCD* _manager;
|
inline static std::set<std::shared_ptr<AcquisitionProcess>> acqProcSptr{};
|
||||||
|
|
||||||
std::shared_ptr<acq_params_t> _acqParams{};
|
std::shared_ptr<acq_params_t> _acqParams{};
|
||||||
std::unique_ptr<ushort[]> _imageBuffer{};
|
|
||||||
size_t _imageBufferSize = 0;
|
|
||||||
size_t _imageBufferRows = 0;
|
|
||||||
|
|
||||||
std::future<void> _snapAndCopyFuture;
|
enum int8_t { STATUS_IDLE, STATUS_ARMED, STATUS_ACQ, STATUS_READ, STATUS_SAVE };
|
||||||
// std::future<void> _saveFitsFileFuture;
|
|
||||||
|
|
||||||
std::string _statusString{CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()};
|
|
||||||
enum int8_t { STATUS_IDLE, STATUS_ACQ, STATUS_READ, STATUS_SAVE };
|
|
||||||
std::atomic_int8_t _status = STATUS_IDLE;
|
std::atomic_int8_t _status = STATUS_IDLE;
|
||||||
std::mutex _statusMutex;
|
std::mutex _statusMutex;
|
||||||
};
|
};
|
||||||
@ -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
|
||||||
@ -280,7 +285,7 @@ private:
|
|||||||
|
|
||||||
// acquisition process members
|
// acquisition process members
|
||||||
std::mutex _acqProcessesMutex;
|
std::mutex _acqProcessesMutex;
|
||||||
std::list<std::weak_ptr<AcquisitionProcess>> _acqProcesses{};
|
// std::list<std::weak_ptr<AcquisitionProcess>> _acqProcesses{};
|
||||||
|
|
||||||
// std::future<void> _doSnapAndCopyFuture;
|
// std::future<void> _doSnapAndCopyFuture;
|
||||||
// std::future<void> _saveFitsFile;
|
// std::future<void> _saveFitsFile;
|
||||||
|
|||||||
@ -16,8 +16,10 @@ enum class RaptorEagleCCDError : int {
|
|||||||
ERROR_CANNOT_RESET_FPGA,
|
ERROR_CANNOT_RESET_FPGA,
|
||||||
ERROR_EXT_TRIGGER_MODE,
|
ERROR_EXT_TRIGGER_MODE,
|
||||||
ERROR_ACQUISITION_IN_PROGRESS,
|
ERROR_ACQUISITION_IN_PROGRESS,
|
||||||
|
ERROR_CANNOT_START_ACQUISITION,
|
||||||
ERROR_INVALID_PATH,
|
ERROR_INVALID_PATH,
|
||||||
ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS
|
ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS,
|
||||||
|
ERROR_NO_FREE_BUFFER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -64,10 +66,14 @@ struct RaptorEagleCCDErrorCategory : std::error_category {
|
|||||||
return "try to use software trigger while external trigger mode is enabled";
|
return "try to use software trigger while external trigger mode is enabled";
|
||||||
case RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS:
|
case RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS:
|
||||||
return "acquisition is in progress";
|
return "acquisition is in progress";
|
||||||
|
case RaptorEagleCCDError::ERROR_CANNOT_START_ACQUISITION:
|
||||||
|
return "cannot start acquisition";
|
||||||
case RaptorEagleCCDError::ERROR_INVALID_PATH:
|
case RaptorEagleCCDError::ERROR_INVALID_PATH:
|
||||||
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";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user