diff --git a/raptor_eagle_cameralink.h b/raptor_eagle_cameralink.h index eb23f37..4fa49eb 100644 --- a/raptor_eagle_cameralink.h +++ b/raptor_eagle_cameralink.h @@ -91,6 +91,16 @@ static constexpr double DAC_CALIBRATION_POINT_1 = 0.0; // at 0 Celcius degree static constexpr double DAC_CALIBRATION_POINT_2 = 40.0; // at +40 Celcius degree +/* REGISTER ADDRESSES */ + +static constexpr std::initializer_list CL_EXPTIME_ADDR = {0xED, 0xEE, 0xEF, 0xF0, 0xF1}; +static constexpr std::initializer_list CL_FRAMERATE_ADDR = {0xDC, 0xDD, 0xDE, 0xDF, 0xE0}; + +static constexpr std::initializer_list CL_ROILEFT_ADDR = {0xB6, 0xB7}; +static constexpr std::initializer_list CL_ROITOP_ADDR = {0xBA, 0xBB}; +static constexpr std::initializer_list CL_ROIWIDTH_ADDR = {0xB4, 0xB5}; +static constexpr std::initializer_list CL_ROIHEIGHT_ADDR = {0xB8, 0xB9}; + /* COMMANDS */ static unsigned char CL_COMMAND_SET_ADDRESS[] = { diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index 4adf231..9fa4dda 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -1,3 +1,4 @@ +#include #include #include "raptor_eagle_cameralink.h" @@ -32,21 +33,33 @@ auto computeChecksum(const R& bytes, bool final_etx = true) } // assume that least significant byte is the last one in 'bytes' +// only the first 5 elements of the input range are taken template size_t convert40BitToCounts(const R& bytes) requires std::same_as, unsigned char> { - size_t counts = 0, i = std::ranges::size(bytes); + // size_t counts = 0, i = std::ranges::size(bytes); - for (auto& byte : bytes) { - counts += byte << (--i * 8); + // for (auto& byte : bytes| std::views::take(5)) { + // counts += byte << (--i * 8); + // } + + if (std::ranges::size(bytes) == 0) + return 0; + + size_t counts = *bytes.begin(); + for (auto& byte : bytes | std::views::drop(1) | std::views::take(4)) { + counts <<= 8; + counts |= byte; } return counts; } -template R> +// NOTE: it is assumed little-endian host's platform!!! +// return an range with least significant byte in the end of the range +template R = std::vector> R convertCountsTo40Bit(uint64_t counts) { R res; @@ -59,6 +72,42 @@ R convertCountsTo40Bit(uint64_t counts) return res; } + +// assume that least significant byte is the last one in 'bytes' +// only the first 2 elements of the input range are taken +template +uint16_t convert12BitToUInt(const R& bytes) + requires std::same_as, unsigned char> +{ + if (std::ranges::size(bytes) == 0) + return 0; + + auto v = bytes | std::views::reverse | std::views::take(2); + + if (std::ranges::size(bytes) > 1) { + return *v.begin() + ((*(++v.begin()) & 0x0F) << 8); + } else { + return *v.begin(); + } +} + + +// NOTE: it is assumed little-endian host's platform!!! +// return an range with least significant byte in the end of the range +template R = std::vector> +R convertUIntTo12Bit(uint16_t counts) +{ + R res; + + auto sp = std::span(reinterpret_cast(&counts), 2); + + // least significant byte in the end of the output range + std::ranges::copy(sp | std::views::reverse, std::back_inserter(res)); + + return res; +} + + } // namespace details @@ -73,8 +122,7 @@ RaptorEagleCCD::RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epi _epixFmtVideoFilename(), _cameraUnitmap(1), // by default only the single camera _clCommandAckBit(1), // enable by default (at camera boot up) - _clChecksumBit(1), // enable by default (at camera boot up) - _expTime(0.0) + _clChecksumBit(1) // enable by default (at camera boot up) { addMarkToPattern("EAGLE-CCD"); @@ -368,28 +416,74 @@ void RaptorEagleCCD::initAttrComm() addAttribute( CAMERA_ATTR_EXPTIME, [this]() { - logTrace("Return acquision duration (current value is {})", _expTime); + auto bytes = readRegisters(CL_EXPTIME_ADDR); + size_t counts = details::convert40BitToCounts(bytes); + double exp_time = counts * 2.5E-8; // counts of 25nsec ticks - return _expTime; + logTrace("Return acquision duration (current value is {} seconds ({} 25nsec ticks))", exp_time, counts); + + return exp_time; }, [this](const double& exp_time) { logDebug("Try to set acquisition duration to {} seconds ...", exp_time); + double etime; - if (_expTime < 0.0) { + if (exp_time < 0.0) { logWarn("Acquisition duration must be non-negative!"); - _expTime = 0.0; - } else if (_expTime > EAGLE_CAMERA_MAX_EXPTIME) { + etime = 0.0; + } else if (exp_time > EAGLE_CAMERA_MAX_EXPTIME) { logWarn("Acquisition duration must not be greater than {} seconds!", EAGLE_CAMERA_MAX_EXPTIME); - _expTime = EAGLE_CAMERA_MAX_EXPTIME; + etime = EAGLE_CAMERA_MAX_EXPTIME; } else { - _expTime = exp_time; + etime = exp_time; } - logDebug("Acquisition duration is set to {} second", _expTime); + size_t counts = static_cast(std::round(etime / 2.5E-8)); + auto bytes = details::convertCountsTo40Bit(counts); + writeRegisters(CL_EXPTIME_ADDR, bytes); + + logDebug("Acquisition duration is set to {} second ({} 25nsec ticks)", etime, counts); }); + + // frame rate + addAttribute( + CAMERA_ATTR_FRAME_RATE, + [this]() { + auto bytes = readRegisters(CL_FRAMERATE_ADDR); + size_t counts = details::convert40BitToCounts(bytes); + + size_t rate = counts * 40; // in MHz + + logTrace("Return frame rate (current value is {} MHz ({} 40MHz ticks))", rate, counts); + + return rate; + }, + [this](const size_t& rate) { + logDebug("Try to set frame rate to {} MHz ...", rate); + + size_t r; + if (rate < 0) { + logWarn("Frame rate must be non-negative!"); + r = 0; + } else if (rate > EAGLE_CAMERA_MAX_FRAMERATE) { + logWarn("Frame rate must not be greater than {} MHz!", EAGLE_CAMERA_MAX_FRAMERATE); + + r = EAGLE_CAMERA_MAX_FRAMERATE; + } else { + r = rate; + } + + size_t counts = r / 40; + auto bytes = details::convertCountsTo40Bit(counts); + writeRegisters(CL_FRAMERATE_ADDR, bytes); + + logDebug("Frame rate is set to {} MHz ({} 40MHz ticks)", r, counts); + }); + + // number of exposures addAttribute( CAMERA_ATTR_NEXP, @@ -403,4 +497,32 @@ void RaptorEagleCCD::initAttrComm() logDebug("Number of frames in acquisition sequence is set to {}", _frameNumbers); }); + + + auto create12BitAttr = [this](std::string_view name, auto reg_addrs, std::string_view log_mark) { + return RaptorEagleCCD::attribute_t( + name, + [this, reg_addrs, log_mark]() { + auto bytes = readRegisters(reg_addrs); + uint16_t v = details::convert12BitToUInt(bytes); + + logTrace("Return {} (current value: {})", log_mark, v); + + return v; + }, + [this, reg_addrs, log_mark](const uint16_t& val) { logDebug("Try to set {} ...", log_mark); }); + }; + + // ROI left + addAttribute( + CAMERA_ATTR_ROI_LEFT, + [this]() { + auto bytes = readRegisters(CL_ROILEFT_ADDR); + uint16_t v = details::convert12BitToUInt(bytes); + + logTrace("Return ROI X-offset (current value: {})", v); + + return v; + }, + [this](const uint16_t& val) {}); } diff --git a/raptor_eagle_ccd.h b/raptor_eagle_ccd.h index 2b1f0d0..f53cf6e 100644 --- a/raptor_eagle_ccd.h +++ b/raptor_eagle_ccd.h @@ -19,7 +19,11 @@ class RaptorEagleCCD : public adc::AdcGenericDevice