From 6c45f04448313ea043087b00cc71b1bb3f2ca6f8 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 19 Dec 2024 18:43:16 +0300 Subject: [PATCH] rewrite CAMERA_STATUS logics add filesystem permissions checking --- CMakeLists.txt | 2 +- raptor_eagle_acqproc.cpp | 59 ++++++++++++++++++++ raptor_eagle_ccd.cpp | 114 +++++++++++++++++++++++++++------------ raptor_eagle_ccd.h | 15 ++++-- raptor_eagle_exception.h | 5 +- 5 files changed, 153 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 876af43..83dac03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ target_compile_definitions(${RAPTOR_EAGLEV_LIB} PUBLIC USE_ASIO_LIBRARY USE_SPDL # !!!!! TEMPORARY !!!!! target_include_directories(${RAPTOR_EAGLEV_LIB} PUBLIC "../ADC/") target_include_directories(${RAPTOR_EAGLEV_LIB} PUBLIC ${XCLIB_INCLUDE_DIR} ${CFITSIO_INCLUDE_DIR}) -target_link_libraries(${RAPTOR_EAGLEV_LIB} PUBLIC Threads::Threads atomic spdlog::spdlog_header_only ${XCLIB_LIBRARIES} ${CFITSIO_LIBRARY}) +target_link_libraries(${RAPTOR_EAGLEV_LIB} PUBLIC Threads::Threads spdlog::spdlog_header_only ${XCLIB_LIBRARIES} ${CFITSIO_LIBRARY}) set(RAPTOR_EAGLEV_SERVER raptor_eaglev_server) diff --git a/raptor_eagle_acqproc.cpp b/raptor_eagle_acqproc.cpp index 0dc14ac..fc5587e 100644 --- a/raptor_eagle_acqproc.cpp +++ b/raptor_eagle_acqproc.cpp @@ -89,6 +89,11 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; + return; } @@ -147,6 +152,12 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; + throw; } @@ -155,9 +166,21 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrfilename.empty()) { _manager->logWarn("An empty FITS filename is given! Do not save acquired image!"); + + _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; } + _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 fname += _acqParams->filename; @@ -362,6 +385,10 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr_cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; + fits_get_errstatus(status, err_str); if (status) { @@ -392,3 +419,35 @@ void RaptorEagleCCD::AcquisitionProcess::stop(bool save) _manager->logWarn("There was no active acquisition process! Ignore!"); } } + + +std::string RaptorEagleCCD::AcquisitionProcess::status() +{ + std::lock_guard lock(_statusMutex); + + switch (_status) { + case STATUS_IDLE: + _statusString = std::format("{}", CAMERA_ATTR_CAMERA_STATUS_IDLE); + break; + case STATUS_ACQ: { + std::chrono::duration curr_exp = _acqParams->abortTime - _acqParams->startTime; + if (curr_exp.count() <= 0) { + _status = STATUS_READ; + _statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename); + } else { + _statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_ACQ, curr_exp.count()); + } + break; + } + case STATUS_READ: + _statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_READ, _acqParams->filename); + break; + case STATUS_SAVE: + _statusString = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_SAVE, _acqParams->filename); + break; + default: + _statusString = "UNKNOWN"; // is should not be!!! + } + + return _statusString; +} diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index 991cede..79ce788 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "raptor_eagle_cameralink.h" #include "raptor_eagle_ccd.h" @@ -410,6 +412,14 @@ bool RaptorEagleCCD::initCamera(int unitmap) throw std::system_error(RaptorEagleCCDError::ERROR_INVALID_UNITMAP); } + std::string status = (*this)[CAMERA_ATTR_CAMERA_STATUS]; + if (status != CAMERA_ATTR_CAMERA_STATUS_IDLE) { + logWarn("It seems camera current status is not IDLE! Abort possible exposure!"); + (*this)[CAMERA_CMD_ABORT_EXP]; + // _cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; + } + AcquisitionProcess::isAcqInProgress = false; // ??????!!!!!!!!!!! + _cameraUnitmap = unitmap; // configure CameraLink serial connection @@ -472,6 +482,19 @@ bool RaptorEagleCCD::initCamera(int unitmap) // setTriggerRegisterBit(CL_TRIGGER_MODE_ABORT_CURRENT_EXP_BIT); + _permanentFitsKeywords.clear(); + _currentFitsKeywords.clear(); + + + // xclibApiCall(pxd_eventFieldClose(_cameraUnitmap, SIGUSR2), + // std::format("pxd_eventFieldClose({}, {})", _cameraUnitmap, SIGUSR2)); + + // xclibApiCall(pxd_eventFieldCreate(_cameraUnitmap, SIGUSR2, NULL), + // std::format("pxd_eventFieldCreate({}, {}, NULL)", _cameraUnitmap, SIGUSR2)); + + // std::signal(SIGUSR2, [this](int signo) { logDebug("SIGUSR2 SIGNAL IS RECEIVED!!!"); + // }); + logInfo("Camera with unitmap '{}' is initialized", _cameraUnitmap); return true; @@ -488,8 +511,8 @@ void RaptorEagleCCD::openPIXCI() } else { xclibApiCall(pxd_PIXCIopen("", "DEFAULT", ""), "pxd_PIXCIopen(\"\", \"DEFAULT\", \"\")"); -// #include DEFAULT_EPIX_VIDEO_FMT_FILE // exported from XCAP (Linux 64-bit!): bin 1x1, full CCD frame -#include "raptor_eagle-v.fmt" // exported from XCAP (Linux 64-bit!): bin 1x1, full CCD frame +#include DEFAULT_EPIX_VIDEO_FMT_FILE // exported from XCAP (Linux 64-bit!): bin 1x1, full CCD frame + // #include "raptor_eagle-v.fmt" // exported from XCAP (Linux 64-bit!): bin 1x1, full CCD frame pxd_videoFormatAsIncludedInit(0); xclibApiCall(pxd_videoFormatAsIncluded(0), "pxd_videoFormatAsIncluded(0)"); } @@ -521,7 +544,8 @@ size_t RaptorEagleCCD::clRead(byte_seq_t& bytes) std::format("pxd_serialRead({}, 0, NULL, 0)", _cameraUnitmap), spdlog::level::trace); if (!nbytes) { - logWarn("There are no bytes in Rx-buffer! Polling buffer during {} ...", CL_DEFAULT_TIMEOUT); + // logWarn("There are no bytes in Rx-buffer! Polling buffer during {} ...", CL_DEFAULT_TIMEOUT); + logTrace("There are no bytes in Rx-buffer! Polling buffer during {} ...", CL_DEFAULT_TIMEOUT); while ((std::chrono::steady_clock::now() - start_tp) <= CL_DEFAULT_TIMEOUT) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); nbytes = pxd_serialRead(_cameraUnitmap, 0, nullptr, 0); @@ -638,9 +662,11 @@ size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes) // send trailing ETX and possible checksum bytes if (tr_nbytes > 1) { - logDebug("Write trailing ETX and checksum bytes"); + // logDebug("Write trailing ETX and checksum bytes"); + logTrace("Write trailing ETX and checksum bytes"); } else { - logDebug("Write trailing ETX byte"); + // logDebug("Write trailing ETX byte"); + logTrace("Write trailing ETX byte"); } xclibApiCall(pxd_serialWrite(_cameraUnitmap, 0, (char*)etx_checksum_bytes, tr_nbytes), @@ -968,6 +994,17 @@ void RaptorEagleCCD::startAquisition() .currentKeywords = std::move(_currentFitsKeywords) // move!!! })); + // check filesystem + std::filesystem::path pt(acq_pars->filename); + auto perms = std::filesystem::status(pt.parent_path()).permissions(); + bool good_perm = (std::filesystem::perms::owner_write & perms) != std::filesystem::perms::none; + good_perm &= (std::filesystem::perms::owner_exec & perms) != std::filesystem::perms::none; + + if (!good_perm) { + logError("Invalid FITS-image filename! Insufficient filesystem permissions!"); + throw std::system_error(RaptorEagleCCDError::ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS); + } + // adjust geometry // auto dv = std::div(_dimCCD[0] - acq_pars->roiStartX, acq_pars->binX); @@ -1029,6 +1066,12 @@ void RaptorEagleCCD::startAquisition() if (status == 0) { logError("CANNOT START ACQUIRING!!!"); } + + // std::lock_guard lock(sptr->_statusMutex); + sptr->_status = AcquisitionProcess::STATUS_IDLE; + // sptr->_status = std::format("{} {}", CAMERA_ATTR_CAMERA_STATUS_ACQ, sptr->_acqParams->expTime); + + // _cameraStatus = CAMERA_ATTR_CAMERA_STATUS_ACQ; } @@ -1173,42 +1216,43 @@ void RaptorEagleCCD::initAttrComm() /* ------- ATTRIBUTES ------- */ - /* CAMERA CURRENT STATUS */ + /* CAMERA CURRENT STATUS (READ-ONLY) */ - addAttribute( - CAMERA_ATTR_CAMERA_STATUS, - [this]() { - logTrace("Return current camera status as {}", _cameraStatus.load()); - return _cameraStatus.load(); - }, - [this](const std::string_view& status) { - logDebug("Try to set current status to {}", status); + addAttribute(CAMERA_ATTR_CAMERA_STATUS, [this]() { + std::lock_guard lock_guard(_acqProcessesMutex); - if (status != CAMERA_ATTR_CAMERA_STATUS_ACQ && status != CAMERA_ATTR_CAMERA_STATUS_READ && - status != CAMERA_ATTR_CAMERA_STATUS_SAVE && status != CAMERA_ATTR_CAMERA_STATUS_IDLE) { - logError("Invalid value of camera status!!!"); - throw std::system_error(); + std::string s, s_head; + + if (!_acqProcesses.empty()) { + for (auto it = _acqProcesses.begin(); it != _acqProcesses.end();) { + if (it->expired()) { + it = _acqProcesses.erase(it); + } else { + auto sptr = it->lock(); + auto st = sptr->status(); + if (st.substr(0, 3) == "ACQ") { // if the camera is acquiring then + s_head = st + ", "; // return it at the beginning of the status string + } else { + std::ranges::copy(st, std::back_inserter(s)); + s += ", "; + } + } } + } - _cameraStatus = status; - logDebug("Camera status is {}", _cameraStatus.load()); - }, - adc::utils::AdcDefaultValueConverter<>::serialize, - [&comp_case_ignore](const attribute_t::serialized_t& v) { - if (std::ranges::equal(v, CAMERA_ATTR_CAMERA_STATUS_ACQ, comp_case_ignore)) { - return CAMERA_ATTR_CAMERA_STATUS_ACQ; - } else if (std::ranges::equal(v, CAMERA_ATTR_CAMERA_STATUS_READ, comp_case_ignore)) { - return CAMERA_ATTR_CAMERA_STATUS_READ; - } else if (std::ranges::equal(v, CAMERA_ATTR_CAMERA_STATUS_SAVE, comp_case_ignore)) { - return CAMERA_ATTR_CAMERA_STATUS_SAVE; - } else if (std::ranges::equal(v, CAMERA_ATTR_CAMERA_STATUS_IDLE, comp_case_ignore)) { - return CAMERA_ATTR_CAMERA_STATUS_IDLE; - } else { - return CAMERA_ATTR_STR_INVALID; + if (!s.empty() || !s_head.empty()) { + s = s_head + s; + if (_acqProcesses.size() == 1) { + s.resize(s.size() - 2); // delete trailing ", " } + } else { + s = std::string{CAMERA_ATTR_CAMERA_STATUS_IDLE.begin(), CAMERA_ATTR_CAMERA_STATUS_IDLE.end()}; + } - return CAMERA_ATTR_STR_INVALID; - }); + logTrace("Return current camera status as {}", s); + + return s; + }); diff --git a/raptor_eagle_ccd.h b/raptor_eagle_ccd.h index a180fd5..d5e21c7 100644 --- a/raptor_eagle_ccd.h +++ b/raptor_eagle_ccd.h @@ -209,6 +209,7 @@ private: void start(const std::shared_ptr& params); // asynchronous method! void stop(bool save = true); + std::string status(); private: inline static std::atomic_bool isAcqInProgress = false; @@ -221,6 +222,11 @@ private: std::future _snapAndCopyFuture; // std::future _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::mutex _statusMutex; }; std::string _epixFmtVideoFilename; @@ -246,11 +252,10 @@ private: // attributes inner variables std::atomic_size_t _frameNumbers; - std::string _currentFitsFile; // current acquisition FITS filename - std::string _currentTemplateFile; // CFITSIO template filename - std::vector _currentFitsKeywords{}; // current acquisition FITS keywords - std::vector _permanentFitsKeywords{}; // permanent user FITS keywords - std::atomic _cameraStatus = CAMERA_ATTR_CAMERA_STATUS_IDLE; // camera current status + std::string _currentFitsFile; // current acquisition FITS filename + std::string _currentTemplateFile; // CFITSIO template filename + std::vector _currentFitsKeywords{}; // current acquisition FITS keywords + std::vector _permanentFitsKeywords{}; // permanent user FITS keywords // std::list> _acqRingBuffer; std::list, size_t>> _acqRingBuffer; diff --git a/raptor_eagle_exception.h b/raptor_eagle_exception.h index a67fd07..448b156 100644 --- a/raptor_eagle_exception.h +++ b/raptor_eagle_exception.h @@ -15,7 +15,8 @@ enum class RaptorEagleCCDError : int { ERROR_CANNOT_RESET_MICRO, ERROR_CANNOT_RESET_FPGA, ERROR_EXT_TRIGGER_MODE, - ERROR_ACQUISITION_IN_PROGRESS + ERROR_ACQUISITION_IN_PROGRESS, + ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS }; @@ -62,6 +63,8 @@ struct RaptorEagleCCDErrorCategory : std::error_category { return "try to use software trigger while external trigger mode is enabled"; case RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS: return "acquisition is in progress"; + case RaptorEagleCCDError::ERROR_INSUFFICIENT_FILESYSTEM_PERMISSIONS: + return "insufficient filesystem permissions"; default: return "UNKNOWN ERROR"; }