From 3b1c1a3e72d21052b397bfd152adc9e0960fa6de Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Sat, 7 Dec 2024 01:27:07 +0300 Subject: [PATCH] ... --- CMakeLists.txt | 3 +- raptor_eagle_acqproc.cpp | 88 ++++++++++++++++++++++++++ raptor_eagle_cameralink.h | 3 + raptor_eagle_ccd.cpp | 129 ++++++++++++++++++++++++++++---------- raptor_eagle_ccd.h | 35 +++++++++-- raptor_eagle_exception.h | 8 ++- 6 files changed, 227 insertions(+), 39 deletions(-) create mode 100644 raptor_eagle_acqproc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3729e87..e31397d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,8 @@ set(RAPTOR_EAGLEV_LIB raptor_eaglev) add_library(${RAPTOR_EAGLEV_LIB} SHARED raptor_eagle_ccd.h raptor_eagle_ccd.cpp raptor_eagle_cameralink.h - raptor_eagle_exception.h) + raptor_eagle_exception.h + raptor_eagle_acqproc.cpp) # to activate spdlog-library support in ADC-library target_compile_definitions(${RAPTOR_EAGLEV_LIB} PRIVATE USE_SPDLOG_LIBRARY) diff --git a/raptor_eagle_acqproc.cpp b/raptor_eagle_acqproc.cpp new file mode 100644 index 0000000..4e30fa2 --- /dev/null +++ b/raptor_eagle_acqproc.cpp @@ -0,0 +1,88 @@ +#include +#include "raptor_eagle_ccd.h" + + +/*******************************************************************************/ +/* ======= RaptorEagleCCD::AcquisitionProcess CLASS IMPLEMENTATION ======= */ +/*******************************************************************************/ + + +RaptorEagleCCD::AcquisitionProcess::AcquisitionProcess(RaptorEagleCCD* manager) : _manager(manager) +{ + std::stringstream st; + st << std::this_thread::get_id(); + _manager->logDebug("Create acquisition process (thread id: {})", st.str()); +} + + +RaptorEagleCCD::AcquisitionProcess::~AcquisitionProcess() +{ + std::stringstream st; + st << std::this_thread::get_id(); + _manager->logDebug("Delete acquisition process (thread id: {})", st.str()); +} + + +void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr& params) +{ + // _acqParams = std::move(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::chrono::milliseconds timeout = + CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT + + std::chrono::milliseconds(static_cast(_acqParams->expTime * 1000)); + + static char color_space[] = "Grey"; + std::stringstream st; + st << std::this_thread::get_id(); + + _manager->logDebug("Arm grabber and wait for acquisition starting trigger (thread id: {}) ...", st.str()); + + _manager->xclibApiCall(pxd_doSnap(_manager->_cameraUnitmap, 1, timeout.count()), + std::format("pxd_doSnap({},1,{})", _manager->_cameraUnitmap, timeout.count())); + + _manager->logDebug("Capture is finished (thread id: {})!", st.str()); + + _manager->logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str()); + + size_t npix = _acqParams->roiWidth * _acqParams->roiHeight; + + _imageBufferRows = static_cast(std::ceil(npix / _manager->_dimCCD[0])); + size_t sz = _imageBufferRows * npix; + + if (_imageBufferSize < 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, + _imageBufferRows, (void*)_imageBuffer.get(), _imageBufferSize, color_space); + + _manager->xclibApiCall(pxd_readushort(_manager->_cameraUnitmap, 1, 0, 0, -1, _imageBufferRows, + _imageBuffer.get(), _imageBufferSize, (char*)color_space), + log_str); + + isAcqInProgress = false; + + // save to FITS file + }); +} + + +void RaptorEagleCCD::AcquisitionProcess::stop(bool save) +{ + if (isAcqInProgress) { + _manager->logInfo("Abort current acquisition process!"); + + auto bytes = _manager->readRegisters({0xD4}); // trigger mode register + bytes[0] |= CL_ABORT_CURRENT_EXP; // set abort acquisition bit + _manager->writeRegisters({0xD4}, bytes); + + _acqParams->abortTime = std::chrono::utc_clock::now(); + _acqParams->saveInAbort = save; + } else { + _manager->logWarn("There was no active acquisition process! Ignore!"); + } +} diff --git a/raptor_eagle_cameralink.h b/raptor_eagle_cameralink.h index 2ca24cc..3460488 100644 --- a/raptor_eagle_cameralink.h +++ b/raptor_eagle_cameralink.h @@ -108,6 +108,9 @@ static constexpr unsigned char CL_TRIGGER_MODE_FFR = 0b00000110; static constexpr unsigned char CL_TRIGGER_MODE_ITR = 0b00000100; static constexpr unsigned char CL_TRIGGER_MODE_SNAPSHOT = 0; // just clear all bits +static constexpr unsigned char CL_ABORT_CURRENT_EXP = 0b00001000; + + /* SETUP CONTROL VALUES */ // shutter diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index a54c6a8..5049414 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -751,47 +751,109 @@ void RaptorEagleCCD::getFPGAVersion() /* ACQUISITION PROCESS */ -void RaptorEagleCCD::startAquisition(acq_params_t acq_pars) +void RaptorEagleCCD::startAquisition() { - acq_pars.startTime = std::chrono::utc_clock::now(); - std::chrono::milliseconds snap_tm = - CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT + - std::chrono::milliseconds(static_cast(acq_pars.expTime * 1000)); + // if (_isAcqInProgress) { + if (AcquisitionProcess::isAcqInProgress) { + logError("Acquisition is in progress! Exit!"); + throw std::error_code(RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS); + } - _doSnapAndCopyFuture = std::async( - std::launch::async, - [acq_pars = std::move(acq_pars), this](std::chrono::milliseconds timeout) mutable { - static char color_space[] = "Grey"; - std::stringstream st; - st << std::this_thread::get_id(); + auto bytes = readRegisters({0xD4}); // trigger mode register + std::bitset<8> bits(bytes[0]); - logDebug("Arm grabber and wait for acquisition start trigger (thread id: {}) ...", st.str()); + if (bits.test(CL_TRIGGER_MODE_EXT_TRIGGER_BIT)) { + logError("External trigger mode is set! Nothing to do, exit!"); + throw std::error_code(RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE); + } - xclibApiCall(pxd_doSnap(_cameraUnitmap, 1, timeout.count()), - std::format("pxd_doSnap({},1,{})", _cameraUnitmap, timeout.count())); - logDebug("Capture is finished (thread id: {})!", st.str()); + logInfo("Start acquisition process"); - logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str()); - size_t npix = acq_pars.roiWidth * acq_pars.roiHeight; + auto acq_pars = std::make_shared(acq_params_t({ + .startTime = std::chrono::utc_clock::time_point(), + .abortTime = std::chrono::utc_clock::time_point(), + .saveInAbort = false, + .expTime = (*this)[CAMERA_ATTR_EXPTIME], + .roiStartX = (*this)[CAMERA_ATTR_ROI_STARTX], + .roiStartY = (*this)[CAMERA_ATTR_ROI_STARTY], + .roiWidth = (*this)[CAMERA_ATTR_ROI_WIDTH], + .roiHeight = (*this)[CAMERA_ATTR_ROI_HEIGHT], + .binX = (*this)[CAMERA_ATTR_XBIN], + .binY = (*this)[CAMERA_ATTR_YBIN], + .readRate = (*this)[CAMERA_ATTR_READ_RATE], + .readMode = (*this)[CAMERA_ATTR_READ_MODE], + .filename = (*this)[CAMERA_ATTR_FITS_FILENAME], + .templateFilename = (*this)[CAMERA_ATTR_FITS_TEMPLATE], + .permanentKeywords = _permanentFitsKeywords, // copy + .currentKeywords = std::move(_currentFitsKeywords) // move!!! - acq_pars.imageBufferRows = static_cast(std::ceil(npix / _dimCCD[0])); - size_t sz = acq_pars.imageBufferRows * npix; + })); - if (acq_pars.imageBufferSize < sz) { - acq_pars.imageBufferSize = sz; - acq_pars.imageBuffer.reset(new ushort[sz]); // may thow std::bad_alloc here! - } + // arm grabber + std::make_shared(this)->start(acq_pars); - auto log_str = - std::format("pxd_readushort({}, 1, 0, 0, -1, {}, {}, {}, {})", _cameraUnitmap, acq_pars.imageBufferRows, - (void*)acq_pars.imageBuffer.get(), acq_pars.imageBufferSize, (void*)color_space); - xclibApiCall(pxd_readushort(_cameraUnitmap, 1, 0, 0, -1, acq_pars.imageBufferRows, - acq_pars.imageBuffer.get(), acq_pars.imageBufferSize, (char*)color_space), - log_str); - }, - std::move(snap_tm)); + acq_pars->startTime = std::chrono::utc_clock::now(); + bits.set(CL_TRIGGER_MODE_SNAPSHOT_BIT); // start snapshot + + + // _doSnapAndCopyFuture = std::async(std::launch::async, [acq_pars = std::move(acq_pars), this]() mutable { + // std::chrono::milliseconds timeout = + // CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT + + // std::chrono::milliseconds(static_cast(acq_pars.expTime * 1000)); + + // static char color_space[] = "Grey"; + // std::stringstream st; + // st << std::this_thread::get_id(); + + // logDebug("Arm grabber and wait for acquisition start trigger (thread id: {}) ...", st.str()); + + // xclibApiCall(pxd_doSnap(_cameraUnitmap, 1, timeout.count()), + // std::format("pxd_doSnap({},1,{})", _cameraUnitmap, timeout.count())); + + // logDebug("Capture is finished (thread id: {})!", st.str()); + + // logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str()); + + // size_t npix = acq_pars.roiWidth * acq_pars.roiHeight; + + // acq_pars.imageBufferRows = static_cast(std::ceil(npix / _dimCCD[0])); + // size_t sz = acq_pars.imageBufferRows * npix; + + // if (acq_pars.imageBufferSize < sz) { + // acq_pars.imageBufferSize = sz; + // acq_pars.imageBuffer.reset(new ushort[sz]); // may thow std::bad_alloc here! + // } + + // auto log_str = + // std::format("pxd_readushort({}, 1, 0, 0, -1, {}, {}, {}, \"{}\")", _cameraUnitmap, + // acq_pars.imageBufferRows, + // (void*)acq_pars.imageBuffer.get(), acq_pars.imageBufferSize, color_space); + // xclibApiCall(pxd_readushort(_cameraUnitmap, 1, 0, 0, -1, acq_pars.imageBufferRows, + // acq_pars.imageBuffer.get(), + // acq_pars.imageBufferSize, (char*)color_space), + // log_str); + // }); + + // logInfo("Start acquisition process"); + + // _isAcqInProgress = true; + // acq_pars.startTime = std::chrono::utc_clock::now(); + // bits.set(CL_TRIGGER_MODE_SNAPSHOT_BIT); // start snapshot +} + + +void RaptorEagleCCD::stopAcquisition() +{ + if (_isAcqInProgress) { + logInfo("Abort current acquisition process!"); + auto bytes = readRegisters({0xD4}); // trigger mode register + bytes[0] |= CL_ABORT_CURRENT_EXP; // set abort acquisition bit + writeRegisters({0xD4}, bytes); + } else { + logWarn("There was no active acquisition process! Ignore!"); + } } @@ -1585,7 +1647,10 @@ void RaptorEagleCCD::initAttrComm() logWarn("Invalid trigger mode! Set it to {}!", CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT); } - writeRegisters({0xD4}, {bits}); + // snapshot mode is self-clearing bit so activate it directly in 'startAcquision' method + if (mode != CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT) { + writeRegisters({0xD4}, {bits}); + } logDebug("Trigger mode bits are set to 0b{:08b}", bits); }); diff --git a/raptor_eagle_ccd.h b/raptor_eagle_ccd.h index 48a8fd3..6d72ec5 100644 --- a/raptor_eagle_ccd.h +++ b/raptor_eagle_ccd.h @@ -144,8 +144,9 @@ private: typedef std::vector byte_seq_t; struct acq_params_t { - uint16_t ccdDim[2]; std::chrono::utc_clock::time_point startTime; + std::chrono::utc_clock::time_point abortTime; + bool saveInAbort; double expTime; // in seconds uint16_t roiStartX; uint16_t roiStartY; @@ -160,9 +161,33 @@ private: std::vector permanentKeywords; std::vector currentKeywords; - std::unique_ptr imageBuffer; - size_t imageBufferSize; - size_t imageBufferRows; + // std::unique_ptr imageBuffer; + // size_t imageBufferSize; + // size_t imageBufferRows; + }; + + class AcquisitionProcess : public std::enable_shared_from_this + { + friend class RaptorEagleCCD; + + public: + AcquisitionProcess(RaptorEagleCCD*); + ~AcquisitionProcess(); + + void start(const std::shared_ptr& params); // asynchronous method! + void stop(bool save = true); + + private: + inline static std::atomic_bool isAcqInProgress = false; + + RaptorEagleCCD* _manager; + std::shared_ptr _acqParams; + std::unique_ptr _imageBuffer; + size_t _imageBufferSize; + size_t _imageBufferRows; + + std::future _snapAndCopyFuture; + std::future _saveFitsFileFuture; }; std::string _epixFmtVideoFilename; @@ -270,7 +295,7 @@ private: void getFPGAVersion(); // acquisition process methods - void startAquisition(acq_params_t); + void startAquisition(); void stopAcquisition(); // logging helper methods diff --git a/raptor_eagle_exception.h b/raptor_eagle_exception.h index 24c8140..a4a766b 100644 --- a/raptor_eagle_exception.h +++ b/raptor_eagle_exception.h @@ -12,7 +12,9 @@ enum class RaptorEagleCCDError : int { ERROR_CAMLINK_WRITE, ERROR_CANNOT_INIT_CAMERA, ERROR_CANNOT_RESET_MICRO, - ERROR_CANNOT_RESET_FPGA + ERROR_CANNOT_RESET_FPGA, + ERROR_EXT_TRIGGER_MODE, + ERROR_ACQUISITION_IN_PROGRESS }; @@ -53,6 +55,10 @@ struct RaptorEagleCCDErrorCategory : std::error_category { return "cannot reset camera microcontroller"; case RaptorEagleCCDError::ERROR_CANNOT_RESET_FPGA: return "cannot reset FPGA board"; + case RaptorEagleCCDError::ERROR_EXT_TRIGGER_MODE: + return "try to use software trigger while external trigger mode is enabled"; + case RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS: + return "acquisition is in progress"; default: return "UNKNOWN ERROR"; }