From 4690af8878bc726ee10229c151ac2e62bc3bc35f Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Sun, 15 Dec 2024 21:52:32 +0300 Subject: [PATCH] add adjusting frame geometry and methods to work with trigger register bits --- raptor_eagle_acqproc.cpp | 4 +- raptor_eagle_cameralink.h | 18 +++- raptor_eagle_ccd.cpp | 195 +++++++++++++++++++++++++++++--------- raptor_eagle_ccd.h | 12 ++- 4 files changed, 178 insertions(+), 51 deletions(-) diff --git a/raptor_eagle_acqproc.cpp b/raptor_eagle_acqproc.cpp index f61361c..30cd5f0 100644 --- a/raptor_eagle_acqproc.cpp +++ b/raptor_eagle_acqproc.cpp @@ -199,13 +199,13 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrroiStartX, + fits_update_key_lng(fitsFilePtr, "STARTX", _acqParams->roiStartX + 1, // "+1" to convert to FITS notation "Image area start pixel along X-axis [CCD pixel]", &status); fits_update_key_lng(fitsFilePtr, "CRPIX2", 1, "Reference pixel along Y-axis", &status); fits_update_key_lng(fitsFilePtr, "CRVAL2", 1, "Physical value of the reference pixel", &status); - fits_update_key_lng(fitsFilePtr, "STARTY", _acqParams->roiStartY, + fits_update_key_lng(fitsFilePtr, "STARTY", _acqParams->roiStartY + 1, // "+1" to convert to FITS notation "Image area start pixel along Y-axis [CCD pixel]", &status); fits_update_key_lng(fitsFilePtr, "XBIN", _acqParams->binX, "Horizontal binning", &status); diff --git a/raptor_eagle_cameralink.h b/raptor_eagle_cameralink.h index 3460488..3c769ef 100644 --- a/raptor_eagle_cameralink.h +++ b/raptor_eagle_cameralink.h @@ -106,10 +106,26 @@ static constexpr unsigned char CL_TRIGGER_MODE_EXT_RISING_EDGE = 0b11000000; static constexpr unsigned char CL_TRIGGER_MODE_EXT_FALLING_EDGE = 0b01000000; 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_TRIGGER_MODE_IDLE = 0; // just clear all bits static constexpr unsigned char CL_ABORT_CURRENT_EXP = 0b00001000; +namespace details +{ + +static constexpr std::string_view cl_trigger_register_bit(const size_t pos) +{ + return pos == CL_TRIGGER_MODE_ENABLE_RISING_EDGE_BIT ? "RISING EDGE" + : pos == CL_TRIGGER_MODE_EXT_TRIGGER_BIT ? "EXTERNAL TRIGGER" + : pos == CL_TRIGGER_MODE_ABORT_CURRENT_EXP_BIT ? "ABORT ACQUISITION" + : pos == CL_TRIGGER_MODE_CONTINUOUS_SEQ_BIT ? "SEQUENCE TRIGGER" + : pos == CL_TRIGGER_MODE_FIXED_FRAME_RATE_BIT ? "FIXED FRAME RATE" + : pos == CL_TRIGGER_MODE_SNAPSHOT_BIT ? "SNAPSHOT TRIGGER" + : "UNKNOWN"; +} + +} // namespace details + /* SETUP CONTROL VALUES */ diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index 93930c8..7f2fdff 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -329,6 +329,77 @@ void RaptorEagleCCD::flipFPGAStateBit(const size_t pos) } +std::bitset<8> RaptorEagleCCD::getTriggerRegister() +{ + std::lock_guard log_guard(_camlinkMutex); + + auto bytes = readRegisters({0xD4}); + + std::bitset<8> bits{bytes[0]}; + + logDebug("Get trigger register as 0b{}", bits.to_string()); + + return bits; +} + + +std::chrono::utc_clock::time_point RaptorEagleCCD::setTriggerRegister(const std::bitset<8> bits) +{ + std::lock_guard lock_guard(_camlinkMutex); + + logDebug("Try to set trigger register to 0b{} bits", bits.to_string()); + + uint8_t reg = static_cast(bits.to_ulong()); + + auto tm = std::chrono::utc_clock::now(); + + writeRegisters({0xD4}, {reg}); + + return tm; +} + +std::chrono::utc_clock::time_point RaptorEagleCCD::setTriggerRegisterBit(const size_t bit_pos) +{ + std::lock_guard lock_guard(_camlinkMutex); + + auto bits = getTriggerRegister(); + + logDebug("Try to set '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + + bits.set(bit_pos); + + return setTriggerRegister(bits); +} + + +std::chrono::utc_clock::time_point RaptorEagleCCD::clearTriggerRegisterBit(const size_t bit_pos) +{ + std::lock_guard lock_guard(_camlinkMutex); + + auto bits = getTriggerRegister(); + + logDebug("Try to clear '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + + bits.reset(bit_pos); + + return setTriggerRegister(bits); +} + + +std::chrono::utc_clock::time_point RaptorEagleCCD::flipTriggerRegisterBit(const size_t bit_pos) +{ + std::lock_guard lock_guard(_camlinkMutex); + + auto bits = getTriggerRegister(); + + logDebug("Try to flip '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + + bits.flip(bit_pos); + + return setTriggerRegister(bits); +} + + /* PRIVATE METHODS */ bool RaptorEagleCCD::initCamera(int unitmap) @@ -389,7 +460,7 @@ bool RaptorEagleCCD::initCamera(int unitmap) (*this)[CAMERA_ATTR_YBIN] = 1; // IDLE mode - (*this)[CAMERA_ATTR_TRIGGER_MODE] = CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT; + (*this)[CAMERA_ATTR_TRIGGER_MODE] = CAMERA_ATTR_TRIGGER_MODE_IDLE; logInfo("Camera with unitmap '{}' is initialized", _cameraUnitmap); @@ -788,7 +859,7 @@ void RaptorEagleCCD::getHardwareInfo() cnt1 = *reinterpret_cast(_manufacturerData.data() + 14); // at 0C cnt2 = *reinterpret_cast(_manufacturerData.data() + 16); // at +40C - _dacTECSetPointCalibCoeffs[0] = (cnt2 - cnt1) / (DAC_CALIBRATION_POINT_2 - DAC_CALIBRATION_POINT_1); + _dacTECSetPointCalibCoeffs[0] = (DAC_CALIBRATION_POINT_2 - DAC_CALIBRATION_POINT_1) / (cnt2 - cnt1); _dacTECSetPointCalibCoeffs[1] = DAC_CALIBRATION_POINT_2 - _dacTECSetPointCalibCoeffs[0] * cnt2; if (_dacTECSetPointCalibCoeffs[1] > 0.0) { logDebug("Computed DAC-to-Temp linear relation: Temp(C) = {:7.4f}*DAC(counts) + {:6.2f}", @@ -798,9 +869,9 @@ void RaptorEagleCCD::getHardwareInfo() _dacTECSetPointCalibCoeffs[0], std::abs(_dacTECSetPointCalibCoeffs[1])); } - _dacTECSetPointCalibCoeffs[2] = (DAC_CALIBRATION_POINT_2 - DAC_CALIBRATION_POINT_1) / (cnt2 - cnt1); - _dacTECSetPointCalibCoeffs[3] = cnt2 - _dacTECSetPointCalibCoeffs[0] * DAC_CALIBRATION_POINT_2; - logDebug("Computed Temp-to-Dac linear relation: DAC(counts) = {}*Temp(C)+{}", _dacTECSetPointCalibCoeffs[2], + _dacTECSetPointCalibCoeffs[2] = (cnt2 - cnt1) / (DAC_CALIBRATION_POINT_2 - DAC_CALIBRATION_POINT_1); + _dacTECSetPointCalibCoeffs[3] = cnt2 - _dacTECSetPointCalibCoeffs[2] * DAC_CALIBRATION_POINT_2; + logDebug("Computed Temp-to-Dac linear relation: DAC(counts) = {}*Temp(C) + {}", _dacTECSetPointCalibCoeffs[2], _dacTECSetPointCalibCoeffs[3]); logDebug("---------------------------------"); @@ -844,8 +915,10 @@ void RaptorEagleCCD::startAquisition() throw std::system_error(RaptorEagleCCDError::ERROR_ACQUISITION_IN_PROGRESS); } - auto bytes = readRegisters({0xD4}); // trigger mode register - std::bitset<8> bits(bytes[0]); + // auto bytes = readRegisters({0xD4}); // trigger mode register + // std::bitset<8> bits(bytes[0]); + + auto bits = getTriggerRegister(); if (bits.test(CL_TRIGGER_MODE_EXT_TRIGGER_BIT)) { logError("External trigger mode is set! Nothing to do, exit!"); @@ -861,10 +934,10 @@ void RaptorEagleCCD::startAquisition() .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], + .roiStartX = (*this)[CAMERA_ATTR_ROI_STARTX], // 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 + .roiHeight = (*this)[CAMERA_ATTR_ROI_HEIGHT], // in binned pixels .binX = (*this)[CAMERA_ATTR_XBIN], .binY = (*this)[CAMERA_ATTR_YBIN], .shutterState = (*this)[CAMERA_ATTR_SHUTTER_STATE], @@ -883,10 +956,23 @@ void RaptorEagleCCD::startAquisition() // adjust geometry - auto w = acq_pars->roiWidth / acq_pars->binX; + auto dv = std::div(_dimCCD[0] - acq_pars->roiStartX, acq_pars->binX); + auto width_max = dv.quot + (dv.rem ? 1 : 0); - if (acq_pars->binX > 1) { + dv = std::div(_dimCCD[1] - acq_pars->roiStartY, acq_pars->binY); + auto height_max = dv.quot + (dv.rem ? 1 : 0); + + if (acq_pars->roiWidth > width_max) { + acq_pars->roiWidth = width_max; + logDebug("Adjust ROI width to {}", acq_pars->roiWidth); + (*this)[CAMERA_ATTR_ROI_WIDTH] = width_max; } + if (acq_pars->roiHeight > height_max) { + acq_pars->roiHeight = height_max; + logDebug("Adjust ROI height to {}", acq_pars->roiHeight); + (*this)[CAMERA_ATTR_ROI_HEIGHT] = height_max; + } + std::lock_guard lock_guard(_acqProcessesMutex); @@ -903,14 +989,17 @@ void RaptorEagleCCD::startAquisition() // arm grabber here sptr->start(acq_pars); - bits.set(CL_TRIGGER_MODE_SNAPSHOT_BIT); // start snapshot bit - bytes[0] = static_cast(bits.to_ulong()); + // bits.set(CL_TRIGGER_MODE_SNAPSHOT_BIT); // start snapshot bit + // bytes[0] = static_cast(bits.to_ulong()); - acq_pars->startTime = std::chrono::utc_clock::now(); - writeRegisters({0xD4}, bytes); // write to trigger mode register (start snapshot) + // acq_pars->startTime = std::chrono::utc_clock::now(); + // writeRegisters({0xD4}, bytes); // write to trigger mode register (start snapshot) + + // start acquisition here + acq_pars->startTime = setTriggerRegisterBit(CL_TRIGGER_MODE_SNAPSHOT_BIT); int status; - xclibApiCall(status = pxd_goneLive(_cameraUnitmap, 0), std::format("psxd_goneLive({}, 0)", _cameraUnitmap)); + xclibApiCall(status = pxd_goneLive(_cameraUnitmap, 0), std::format("pxd_goneLive({}, 0)", _cameraUnitmap)); if (status == 0) { logError("CANNOT START ACQUIRING!!!"); } @@ -1267,14 +1356,19 @@ void RaptorEagleCCD::initAttrComm() [this](const T& val) { // validator std::pair res{val, ""}; - if (val < 1) { - res.first = 1; - res.second = "The ROI X-offset must start from 1 (FITS notation)"; - } else if (val > _dimCCD[0]) { - res.first = _dimCCD[0]; - res.second = std::format( - "The ROI X-offset must not be greater than CCD X-dimension of {} pixels (FITS notation)", - _dimCCD[0]); + // if (val < 1) { + // res.first = 1; + // res.second = "The ROI X-offset must start from 1 (FITS notation)"; + // } else if (val > _dimCCD[0]) { + // res.first = _dimCCD[0]; + // res.second = std::format( + // "The ROI X-offset must not be greater than CCD X-dimension of {} pixels (FITS notation)", + // _dimCCD[0]); + // } + if (val >= _dimCCD[0]) { + res.first = _dimCCD[0] - 1; + res.second = + std::format("The ROI X-offset must be lesser than CCD X-dimension of {} pixels", _dimCCD[0]); } return res; @@ -1288,14 +1382,19 @@ void RaptorEagleCCD::initAttrComm() [this](const T& val) { // validator std::pair res{val, ""}; - if (val < 1) { - res.first = 1; - res.second = "The ROI Y-offset must start from 1 (FITS notation)"; - } else if (val > _dimCCD[1]) { - res.first = _dimCCD[1]; - res.second = std::format( - "The ROI Y-offset must not be greater than CCD Y-dimension of {} pixels (FITS notation)", - _dimCCD[1]); + // if (val < 1) { + // res.first = 1; + // res.second = "The ROI Y-offset must start from 1 (FITS notation)"; + // } else if (val > _dimCCD[1]) { + // res.first = _dimCCD[1]; + // res.second = std::format( + // "The ROI Y-offset must not be greater than CCD Y-dimension of {} pixels (FITS notation)", + // _dimCCD[1]); + // } + if (val >= _dimCCD[1]) { + res.first = _dimCCD[1] - 1; + res.second = + std::format("The ROI Y-offset must be lesser than CCD Y-dimension of {} pixels", _dimCCD[1]); } return res; @@ -1314,8 +1413,8 @@ void RaptorEagleCCD::initAttrComm() res.second = "The ROI width must start from 1"; } else if (val > _dimCCD[0]) { res.first = _dimCCD[0]; - res.second = std::format( - "The ROI width must not be greater than CCD dimension of {} pixels (FITS notation)", _dimCCD[0]); + res.second = + std::format("The ROI width must not be greater than CCD dimension of {} pixels", _dimCCD[0]); } return res; @@ -1331,8 +1430,8 @@ void RaptorEagleCCD::initAttrComm() // ROI height can be 0 (see Eagle V 4240 instruction manual) if (val > _dimCCD[1]) { res.first = _dimCCD[1]; - res.second = std::format( - "The ROI height must not be greater than CCD dimension of {} pixels (FITS notation)", _dimCCD[1]); + res.second = + std::format("The ROI height must not be greater than CCD dimension of {} pixels", _dimCCD[1]); } return res; @@ -1737,8 +1836,9 @@ void RaptorEagleCCD::initAttrComm() addAttribute( CAMERA_ATTR_TRIGGER_MODE, [this]() { - auto bytes = readRegisters({0xD4}); - std::bitset<8> bits{bytes[0]}; + // auto bytes = readRegisters({0xD4}); + // std::bitset<8> bits{bytes[0]}; + auto bits = getTriggerRegister(); std::string_view trigger_mode; if (bits.test(CL_TRIGGER_MODE_EXT_TRIGGER_BIT)) { // external trigger enabled, what is the edge? @@ -1757,12 +1857,13 @@ void RaptorEagleCCD::initAttrComm() trigger_mode = CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT; } - logTrace("Return trigger mode as '{}' string (bits = 0b{:08b})", trigger_mode, bytes[0]); + // logTrace("Return trigger mode as '{}' string (bits = 0b{:08b})", trigger_mode, bytes[0]); + logTrace("Return trigger mode as '{}' string (bits = 0b{})", trigger_mode, bits.to_string()); return trigger_mode; }, [this](const std::string_view& mode) { - uchar bits = CL_TRIGGER_MODE_SNAPSHOT; + uchar bits = CL_TRIGGER_MODE_IDLE; if (mode == CAMERA_ATTR_TRIGGER_MODE_EXT_RISING) { bits = CL_TRIGGER_MODE_EXT_RISING_EDGE; logInfo("Trigger mode is set to {}", mode); @@ -1775,18 +1876,20 @@ void RaptorEagleCCD::initAttrComm() } else if (mode == CAMERA_ATTR_TRIGGER_MODE_ITR) { bits = CL_TRIGGER_MODE_ITR; logInfo("Trigger mode is set to {}", mode); - } else if (mode == CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT) { + } else if (mode == CAMERA_ATTR_TRIGGER_MODE_IDLE) { logInfo("Trigger mode is set to {}", mode); } else { - logWarn("Invalid trigger mode! Set it to {}!", CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT); + logWarn("Invalid trigger mode! Set it to {}!", CAMERA_ATTR_TRIGGER_MODE_IDLE); } // // snapshot mode is self-clearing bit so activate it directly in 'startAcquision' method // if (mode != CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT) { - writeRegisters({0xD4}, {bits}); + // writeRegisters({0xD4}, {bits}); // } - logDebug("Trigger mode bits are set to 0b{:08b}", bits); + // logDebug("Trigger mode bits are set to 0b{:08b}", bits); + + setTriggerRegister(bits); }, adc::utils::AdcDefaultValueConverter<>::serialize, [&comp_case_ignore](const attribute_t::serialized_t& v) { diff --git a/raptor_eagle_ccd.h b/raptor_eagle_ccd.h index 457445e..834288d 100644 --- a/raptor_eagle_ccd.h +++ b/raptor_eagle_ccd.h @@ -141,11 +141,13 @@ public: static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_FFR{"FFR"}; // snapshot static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT{"SNAPSHOT"}; + // idle + static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_IDLE{"IDLE"}; RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epix_video_fmt_filename, - std::shared_ptr logger = spdlog::null_logger_mt("EAGLE_CCD_NULLLOGGER")); + std::shared_ptr logger = spdlog::null_logger_mt("EAGLE_CCD_NULL_LOGGER")); - RaptorEagleCCD(std::shared_ptr logger = spdlog::null_logger_mt("EAGLE_CCD_NULLLOGGER")); + RaptorEagleCCD(std::shared_ptr logger = spdlog::null_logger_mt("EAGLE_CCD_NULL_LOGGER")); ~RaptorEagleCCD(); @@ -310,6 +312,12 @@ private: void clearFPGAStateBit(const size_t bit_pos); void flipFPGAStateBit(const size_t bit_pos); + // set 'Abort' bit in trigger register + std::bitset<8> getTriggerRegister(); + std::chrono::utc_clock::time_point setTriggerRegister(const std::bitset<8> bits); + std::chrono::utc_clock::time_point setTriggerRegisterBit(const size_t bit_pos); + std::chrono::utc_clock::time_point clearTriggerRegisterBit(const size_t bit_pos); + std::chrono::utc_clock::time_point flipTriggerRegisterBit(const size_t bit_pos); // reset hardware methods