diff --git a/raptor_eagle_acqproc.cpp b/raptor_eagle_acqproc.cpp index 30cd5f0..9dac956 100644 --- a/raptor_eagle_acqproc.cpp +++ b/raptor_eagle_acqproc.cpp @@ -96,9 +96,24 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrroiWidth, _acqParams->roiHeight, _acqParams->binX, _acqParams->binY); _manager->logDebug("Copy image from grabber to buffer (thread id: {}) ...", st.str()); - size_t npix = _acqParams->roiWidth * _acqParams->roiHeight; + // compute image dimension + // NOTE: _acqParams->roiWidth and _acqParams->roiHeight are expected in CCD pixels (not binned)!!! - _imageBufferRows = static_cast(std::ceil(npix / _manager->_dimCCD[0])); + auto div = std::div(_acqParams->roiWidth, _acqParams->binX); + auto dimx = div.quot + (div.rem ? 1 : 0); + div = std::div(_acqParams->roiHeight, _acqParams->binY); + auto dimy = div.quot + (div.rem ? 1 : 0); + + // LONGLONG npix = _acqParams->roiWidth * _acqParams->roiHeight; + LONGLONG npix = dimx * dimy; + + // NOTE: + auto ldiv = std::lldiv(npix, _manager->_dimCCD[0]); + _imageBufferRows = ldiv.quot + (ldiv.rem ? 1 : 0); + + // _imageBufferRows = static_cast(std::ceil(npix / _manager->_dimCCD[0])); + + // read size size_t sz = _imageBufferRows * _manager->_dimCCD[0]; try { @@ -112,7 +127,7 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrxclibApiCall(pxd_readushort(_manager->_cameraUnitmap, 1, 0, 0, -1, _imageBufferRows, - _imageBuffer.get(), _imageBufferSize, (char*)color_space), + (ushort*)_imageBuffer.get(), _imageBufferSize, (char*)color_space), log_str); isAcqInProgress = false; @@ -138,10 +153,11 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrroiWidth; - naxes[1] = _acqParams->roiHeight; + const int naxis = 2; + long naxes[naxis] = {dimx, dimy}; + // long naxes[2]; + // naxes[0] = _acqParams->roiWidth; + // naxes[1] = _acqParams->roiHeight; char err_str[100]; @@ -154,7 +170,7 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrlogDebug("Write {} pixels to the HDU ...", npix); - fits_write_img(fitsFilePtr, TUSHORT, 1, (LONGLONG)npix, _imageBuffer.get(), &status); + fits_write_img(fitsFilePtr, TUSHORT, 1, npix, (void*)_imageBuffer.get(), &status); // helper to convert std::string_view to C-lang null-terminated string @@ -185,8 +201,8 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrstartTime); fits_update_key_str(fitsFilePtr, "DATE-OBS", str.c_str(), "Start of the exposure in UTC", &status); - fits_update_key_dbl(fitsFilePtr, "JD", jd, -12, "Julian day of exposure start time", &status); - fits_update_key_dbl(fitsFilePtr, "MJD", jd - 2400000.5, -12, "Modified Julian day of exposure start time", + fits_update_key_dbl(fitsFilePtr, "JD", jd, -15, "Julian day of exposure start time", &status); + fits_update_key_dbl(fitsFilePtr, "MJD", jd - 2400000.5, -15, "Modified Julian day of exposure start time", &status); if (_acqParams->startTime < _acqParams->abortTime) { // acquisition was aborted @@ -236,7 +252,7 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptrccdTemp, -2, "CCD chip temperature in Celsius", &status); fits_update_key_dbl(fitsFilePtr, "PCBTEMP", _acqParams->pcbTemp, -2, "PCB temperature in Celsius", &status); - fits_update_key_dbl(fitsFilePtr, "TECSETPT", _acqParams->tecSetPoint, -2, + fits_update_key_dbl(fitsFilePtr, "TECSETPT", _acqParams->tecSetPoint, -5, "TEC set point temperature in Celsius", &status); if (!status) { diff --git a/raptor_eagle_cameralink.h b/raptor_eagle_cameralink.h index 3c769ef..c44c708 100644 --- a/raptor_eagle_cameralink.h +++ b/raptor_eagle_cameralink.h @@ -137,6 +137,7 @@ static constexpr char CL_SHUTTER_EXP = 0x2; // readout rate (registers values) +static constexpr std::initializer_list CL_READOUT_CLOCK_RATE_ADDR = {0xA3, 0xA4}; static constexpr unsigned char CL_READOUT_CLOCK_RATE_A3_2MHZ = 0x02; static constexpr unsigned char CL_READOUT_CLOCK_RATE_A4_2MHZ = 0x02; static constexpr unsigned char CL_READOUT_CLOCK_RATE_A3_75KHZ = 0x43; diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index 7f2fdff..fd00d73 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -364,7 +364,7 @@ std::chrono::utc_clock::time_point RaptorEagleCCD::setTriggerRegisterBit(const s auto bits = getTriggerRegister(); - logDebug("Try to set '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + logDebug("Try to set '{}' trigger register bit", details::cl_trigger_register_bit(bit_pos)); bits.set(bit_pos); @@ -378,7 +378,7 @@ std::chrono::utc_clock::time_point RaptorEagleCCD::clearTriggerRegisterBit(const auto bits = getTriggerRegister(); - logDebug("Try to clear '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + logDebug("Try to clear '{}' trigger register bit", details::cl_trigger_register_bit(bit_pos)); bits.reset(bit_pos); @@ -392,7 +392,7 @@ std::chrono::utc_clock::time_point RaptorEagleCCD::flipTriggerRegisterBit(const auto bits = getTriggerRegister(); - logDebug("Try to flip '{}' trigger register", details::cl_trigger_register_bit(bit_pos)); + logDebug("Try to flip '{}' trigger register bit", details::cl_trigger_register_bit(bit_pos)); bits.flip(bit_pos); @@ -450,18 +450,28 @@ bool RaptorEagleCCD::initCamera(int unitmap) logDebug("Set initial state (IDLE, full frame, binning to 1x1) ..."); - (*this)[CAMERA_ATTR_READ_MODE] = CAMERA_ATTR_READ_MODE_NORMAL; - (*this)[CAMERA_ATTR_READ_RATE] = CAMERA_ATTR_READ_RATE_FAST; - (*this)[CAMERA_ATTR_ROI_STARTX] = 1; // in FITS notation (started from 1)!!! - (*this)[CAMERA_ATTR_ROI_STARTY] = 1; // in FITS notation (started from 1)!!! - (*this)[CAMERA_ATTR_ROI_WIDTH] = _dimCCD[0]; - (*this)[CAMERA_ATTR_ROI_HEIGHT] = _dimCCD[1]; + (*this)[CAMERA_ATTR_XBIN] = 1; (*this)[CAMERA_ATTR_YBIN] = 1; + (*this)[CAMERA_ATTR_ROI_STARTX] = 0; // in CCD notation (started from 0)!!! + (*this)[CAMERA_ATTR_ROI_STARTY] = 0; // in CCD notation (started from 0)!!! + + (*this)[CAMERA_ATTR_ROI_HEIGHT] = 0; // ??!!!! + + (*this)[CAMERA_ATTR_ROI_WIDTH] = _dimCCD[0]; + (*this)[CAMERA_ATTR_ROI_HEIGHT] = _dimCCD[1]; + + (*this)[CAMERA_ATTR_READ_MODE] = CAMERA_ATTR_READ_MODE_NORMAL; + (*this)[CAMERA_ATTR_READ_RATE] = CAMERA_ATTR_READ_RATE_FAST; // IDLE mode (*this)[CAMERA_ATTR_TRIGGER_MODE] = CAMERA_ATTR_TRIGGER_MODE_IDLE; + // clearTriggerRegisterBit(CL_TRIGGER_MODE_EXT_TRIGGER_BIT); + // clearTriggerRegisterBit(CL_TRIGGER_MODE_CONTINUOUS_SEQ_BIT); + + // setTriggerRegisterBit(CL_TRIGGER_MODE_ABORT_CURRENT_EXP_BIT); + logInfo("Camera with unitmap '{}' is initialized", _cameraUnitmap); return true; @@ -521,8 +531,9 @@ size_t RaptorEagleCCD::clRead(byte_seq_t& bytes) } if (!nbytes) { - logWarn("Cameralink reading operation timeout!"); - return 0; + // logWarn("Cameralink reading operation timeout!"); + // return 0; + throw std::system_error(RaptorEagleCCDError::ERROR_CAMLINK_READ_TIMEOUT); } // here the call is only for logging purpose @@ -1438,58 +1449,84 @@ void RaptorEagleCCD::initAttrComm() }, "ROI height")); + + // binning validator (1-32, 64) + auto bin_validator = [](const T& val, std::string_view log_name) { + std::pair res{val, ""}; + + T* limits = (T*)EAGLE_CAMERA_MAX_XBIN; + if (log_name == "YBIN") { + limits = (T*)EAGLE_CAMERA_MAX_YBIN; + } + + if (val < 1) { + res.first = 1; + res.second = std::format("The {} must start from 1", log_name); + } else if ((val > limits[0]) && (val < limits[1])) { + // set to the closest + res.first = (val - limits[0]) < (limits[1] - val) ? limits[0] : limits[1]; + + res.second = std::format("The {} must not be within {} and {}", log_name, limits[0], limits[1]); + } else if (val > limits[1]) { + res.first = limits[1]; + res.second = std::format("The {} must not be greater than {}", log_name, limits[1]); + } + + return res; + }; + + // X-bin - addAttribute(create8BitAttr( - CAMERA_ATTR_XBIN, CL_XBIN_ADDR, - [](const T& val) { // validator (1-32, 64) - std::pair res{val, ""}; + addAttribute(attribute_t::makeArithAttr( + CAMERA_ATTR_XBIN, + [this]() { + auto bytes = readRegisters(CL_XBIN_ADDR); - if (val < 1) { - res.first = 1; - res.second = "The XBIN must start from 1"; - } else if ((val > EAGLE_CAMERA_MAX_XBIN[0]) && (val < EAGLE_CAMERA_MAX_XBIN[1])) { - // set to the closest - res.first = (val - EAGLE_CAMERA_MAX_XBIN[0]) < (EAGLE_CAMERA_MAX_XBIN[1] - val) - ? EAGLE_CAMERA_MAX_XBIN[0] - : EAGLE_CAMERA_MAX_XBIN[1]; + // inner register value of binning starts from 0!!! + logDebug("Return XBIN as {} (inner register value: {})", bytes[0] + 1, bytes[0]); - res.second = std::format("The XBIN must not be within {} and {}", EAGLE_CAMERA_MAX_XBIN[0], - EAGLE_CAMERA_MAX_XBIN[1]); - } else if (val > EAGLE_CAMERA_MAX_XBIN[1]) { - res.first = EAGLE_CAMERA_MAX_XBIN[1]; - res.second = std::format("The XBIN must not be greater than {}", EAGLE_CAMERA_MAX_XBIN[1]); + return bytes[0] + 1; + }, + [&bin_validator, this](const uchar& val) { + logDebug("Try to set XBIN to {} ...", val); + + auto v_res = bin_validator(val, "XBIN"); + if (v_res.second.size()) { + logWarn(v_res.second); } - return res; - }, - "XBIN")); + // inner register value of binning starts from 0!!! + v_res.first -= 1; + writeRegisters(CL_XBIN_ADDR, {v_res.first}); + logDebug("XBIN is set to {} (inner register value {})", v_res.first + 1, v_res.first); + })); // Y-bin - addAttribute(create8BitAttr( - CAMERA_ATTR_YBIN, CL_YBIN_ADDR, - [](const T& val) { // validator (1-32, 64) - std::pair res{val, ""}; + addAttribute(attribute_t::makeArithAttr( + CAMERA_ATTR_YBIN, + [this]() { + auto bytes = readRegisters(CL_YBIN_ADDR); - if (val < 1) { - res.first = 1; - res.second = "The YBIN must start from 1"; - } else if ((val > EAGLE_CAMERA_MAX_YBIN[0]) && (val < EAGLE_CAMERA_MAX_YBIN[1])) { - // set to the closest - res.first = (val - EAGLE_CAMERA_MAX_YBIN[0]) < (EAGLE_CAMERA_MAX_YBIN[1] - val) - ? EAGLE_CAMERA_MAX_YBIN[0] - : EAGLE_CAMERA_MAX_YBIN[1]; + // inner register value of binning starts from 0!!! + logDebug("Return YBIN as {} (inner register value: {})", bytes[0] + 1, bytes[0]); - res.second = std::format("The YBIN must not be within {} and {}", EAGLE_CAMERA_MAX_YBIN[0], - EAGLE_CAMERA_MAX_YBIN[1]); - } else if (val > EAGLE_CAMERA_MAX_YBIN[1]) { - res.first = EAGLE_CAMERA_MAX_YBIN[1]; - res.second = std::format("The YBIN must not be greater than {}", EAGLE_CAMERA_MAX_XBIN[1]); + return bytes[0] + 1; + }, + [&bin_validator, this](const uchar& val) { + logDebug("Try to set YBIN to {} ...", val); + + auto v_res = bin_validator(val, "YBIN"); + if (v_res.second.size()) { + logWarn(v_res.second); } - return res; - }, - "YBIN")); + // inner register value of binning starts from 0!!! + v_res.first -= 1; + writeRegisters(CL_YBIN_ADDR, {v_res.first}); + + logDebug("YBIN is set to {} (inner register value {})", v_res.first + 1, v_res.first); + })); /* TEC SET POINT AND STATE */ @@ -1665,7 +1702,7 @@ void RaptorEagleCCD::initAttrComm() addAttribute( CAMERA_ATTR_READ_RATE, [this]() { - auto bytes = readRegisters(CL_FRAMERATE_ADDR); + auto bytes = readRegisters(CL_READOUT_CLOCK_RATE_ADDR); std::string_view val; if ((bytes[0] == CL_READOUT_CLOCK_RATE_A3_2MHZ) && (bytes[1] == CL_READOUT_CLOCK_RATE_A4_2MHZ)) { @@ -1695,7 +1732,7 @@ void RaptorEagleCCD::initAttrComm() logInfo("Set readout rate to {}", CAMERA_ATTR_READ_RATE_FAST); } - writeRegisters(CL_FRAMERATE_ADDR, bytes); + writeRegisters(CL_READOUT_CLOCK_RATE_ADDR, bytes); logDebug("Readout rate is set to [0x{:02X}, 0x{:02X}] bytes", bytes[0], bytes[1]); }, diff --git a/raptor_eagle_exception.h b/raptor_eagle_exception.h index 864425b..a67fd07 100644 --- a/raptor_eagle_exception.h +++ b/raptor_eagle_exception.h @@ -10,6 +10,7 @@ enum class RaptorEagleCCDError : int { ERROR_INVALID_UNITMAP, ERROR_INVALID_ATTR_VALUE, ERROR_CAMLINK_WRITE, + ERROR_CAMLINK_READ_TIMEOUT, ERROR_CANNOT_INIT_CAMERA, ERROR_CANNOT_RESET_MICRO, ERROR_CANNOT_RESET_FPGA, @@ -49,6 +50,8 @@ struct RaptorEagleCCDErrorCategory : std::error_category { return "invalid camera attribute value"; case RaptorEagleCCDError::ERROR_CAMLINK_WRITE: return "not all data were transmitted via CameraLink connection"; + case RaptorEagleCCDError::ERROR_CAMLINK_READ_TIMEOUT: + return "CameraLink reading operation timeout"; case RaptorEagleCCDError::ERROR_CANNOT_INIT_CAMERA: return "cannot initialize camera hardware"; case RaptorEagleCCDError::ERROR_CANNOT_RESET_MICRO: