This commit is contained in:
Timur A. Fatkhullin 2024-12-02 01:02:11 +03:00
parent 35e7999c3f
commit db79062506
4 changed files with 250 additions and 7 deletions

View File

@ -32,7 +32,7 @@ static constexpr bool CL_DEFAULT_CHK_SUM_ENABLED = true;
static constexpr char CL_ETX = 0x50;
static constexpr char CL_ETX_SER_TIMEOUT = 0x51;
static constexpr char CL_ETX_CK_SUM_ERR = 0x52;
static constexpr char CL_ETXI2C_ERR = 0x53;
static constexpr char CL_ETX_I2C_ERR = 0x53;
static constexpr char CL_ETX_UNKNOWN_CMD = 0x54;
static constexpr char CL_ETX_DONE_LOW = 0x55;

View File

@ -5,6 +5,7 @@
#include "raptor_eagle_ccd.h"
#include "raptor_eagle_exception.h"
#include <common/adc_utils.h>
#define DEFAULT_EPIX_VIDEO_FMT_FILE "raptor_eagle-v.fmt"
@ -12,7 +13,14 @@
RaptorEagleCCD::RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epix_video_fmt_filename,
std::shared_ptr<spdlog::logger> logger)
: base_t("EagleCCD"), adc::AdcSpdlogLogger(logger)
: base_t("EagleCCD"),
adc::AdcSpdlogLogger(logger),
_epixFmtVideoFilename(),
_cameraUnitmap(1), // by default only the single camera
_clCommandAckBit(1), // enable by default
_clChecksumBit(1), // enable by default
_expTime(0.0)
{
addMarkToPattern("EAGLE-CCD");
@ -51,7 +59,12 @@ void RaptorEagleCCD::initCamera(int unitmap)
_cameraUnitmap = unitmap;
logInfo("Camera with unit '{}' is initialized", _cameraUnitmap);
xclibApiCall(pxd_serialConfigure(_cameraUnitmap, 0, CL_DEFAULT_BAUD_RATE, CL_DEFAULT_DATA_BITS, 0,
CL_DEFAULT_STOP_BIT, 0, 0, 0),
std::format("pxd_serialConfigure({}, 0, {}, {}, 0, {}, 0, 0, 0)", _cameraUnitmap, CL_DEFAULT_BAUD_RATE,
CL_DEFAULT_DATA_BITS, CL_DEFAULT_STOP_BIT));
logInfo("Camera with unitmap '{}' is initialized", _cameraUnitmap);
}
@ -77,7 +90,170 @@ void RaptorEagleCCD::closePIXCI()
}
/* CameraLink-RELATED METHODS */
size_t RaptorEagleCCD::clRead(byte_seq_t& bytes)
{
size_t nbytes;
// how many byte are available
xclibApiCall(nbytes = pxd_serialRead(_cameraUnitmap, 0, nullptr, 0),
std::format("pxd_serialRead({}, 0, NULL, 0)", _cameraUnitmap));
if (!nbytes) {
logWarn("There are no bytes in Rx-buffer! Nothing to do!");
return 0;
}
nbytes += _clCommandAckBit + _clChecksumBit;
if (bytes.size() < nbytes) {
bytes.resize(nbytes);
}
xclibApiCall(pxd_serialRead(_cameraUnitmap, 0, bytes.data(), nbytes),
std::format("pxd_serialRead({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), nbytes));
if (_loggerSPtr->level() == spdlog::level::trace) {
std::string s;
adc::utils::AdcCharRangeFromValueRange(s, bytes, std::string_view(", "));
logTrace("Received from controller: [{}]", s);
}
return nbytes;
}
size_t RaptorEagleCCD::clReadAndCheckAck(byte_seq_t& bytes)
{
auto nbytes = clRead(bytes);
if (_clCommandAckBit && nbytes) {
auto ack = *(bytes.end() - 1 - _clChecksumBit);
if (ack != CL_ETX) {
throw std::error_code(ack, RaptorEagleControllerErrorCategory::get());
}
}
return nbytes;
}
size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
{
if (bytes.empty()) {
logWarn("An empty transmitted byte sequence! Nothing to do!");
return 0;
}
if (_loggerSPtr->level() == spdlog::level::trace) {
std::string s;
adc::utils::AdcCharRangeFromValueRange(s, bytes, std::string_view(", "));
logTrace("Send to controller: [{}]", s);
}
size_t nbytes, tr_nbytes = bytes.size();
// how many bytes are available in Tx-buffer
xclibApiCall(nbytes = pxd_serialWrite(_cameraUnitmap, 0, nullptr, 0),
std::format("pxd_serialWrite({}, 0, NULL, 0)", _cameraUnitmap));
if (nbytes) {
tr_nbytes += _clCommandAckBit + _clChecksumBit;
if (nbytes < tr_nbytes) {
logWarn(
"Not enough of available space in the internal Tx-buffer (needs = {}, available = {})! Nothing to do!",
tr_nbytes, nbytes);
nbytes = 0;
} else {
xclibApiCall(
nbytes = pxd_serialWrite(_cameraUnitmap, 0, (char*)bytes.data(), bytes.size()),
std::format("pxd_serialWrite({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), bytes.size()));
if (nbytes != bytes.size()) {
throw std::error_code(RaptorEagleCCDError::ERROR_CAMLINK_WRITE);
}
}
} else {
logWarn("No available space in the internal Tx-buffer! Nothing to do!");
}
return nbytes;
}
/* CREATE COMMANDS AND ATTRIBUTES */
void RaptorEagleCCD::initAttrComm()
{
addAttribute(CAMERA_ATTR_EXPTIME, []() {});
/* commands */
/* attributes */
addAttribute(
CAMERA_ATTR_CAMLINK_SETUP,
[this]() {
logTrace("Return CameraLink setup bits (current values: command-ack = {}, checksum = {})", _clCommandAckBit,
_clChecksumBit);
return std::vector<uint8_t>({_clCommandAckBit, _clChecksumBit});
},
[this](const std::vector<uint8_t>& setup) {
logDebug("Try to set CameraLink setup bits ...");
if (setup.size() < 2) {
throw std::error_code(RaptorEagleCCDError::ERROR_INVALID_ATTR_VALUE);
}
_clCommandAckBit = setup[0] ? 1 : 0;
_clChecksumBit =
(setup[1] && _clCommandAckBit) ? 1 : 0; // checksum will be enabled only if command ack is set
logDebug("Set CameraLink setup bits to: command-ack = {}, checksum = {}", _clCommandAckBit, _clChecksumBit);
});
// exposure time
addAttribute(
CAMERA_ATTR_EXPTIME,
[this]() {
logTrace("Return acquision duration (current value is {})", _expTime);
return _expTime;
},
[this](const double& exp_time) {
logDebug("Try to set acquisition duration to {} seconds ...", exp_time);
if (_expTime < 0.0) {
logWarn("Acquisition duration must be non-negative!");
_expTime = 0.0;
} else if (_expTime > EAGLE_CAMERA_MAX_EXPTIME) {
logWarn("Acquisition duration must not be greater than {} seconds!", EAGLE_CAMERA_MAX_EXPTIME);
_expTime = EAGLE_CAMERA_MAX_EXPTIME;
} else {
_expTime = exp_time;
}
logDebug("Acquisition duration is set to {} second", _expTime);
});
// number of exposures
addAttribute(
CAMERA_ATTR_NEXP,
[this]() {
logTrace("Return number of frames in acquisition sequence (current value is {})", _frameNumbers);
return _frameNumbers;
},
[this](const size_t& nframes) {
_frameNumbers = nframes;
logDebug("Number of frames in acquisition sequence is set to {}", _frameNumbers);
});
}

View File

@ -18,6 +18,9 @@ class RaptorEagleCCD : public adc::AdcGenericDevice<std::string, adc::AdcDeviceA
typedef adc::AdcGenericDevice<std::string, adc::AdcDeviceAttribute<>, adc::AdcDeviceCommand<>> base_t;
public:
/* some Eagle V camera constants */
static constexpr double EAGLE_CAMERA_MAX_EXPTIME = 27487.7906944; // in seconds (0xFFFFFFFFFF * 25nsec)
static constexpr std::string_view CAMERA_ATTR_HBIN{"HBIN"};
static constexpr std::string_view CAMERA_ATTR_VBIN{"VBIN"};
static constexpr std::string_view CAMERA_ATTR_ROI_LEFT{"ROI_LEFT"};
@ -33,6 +36,7 @@ public:
static constexpr std::string_view CAMERA_ATTR_NEXP{"NEXP"};
static constexpr std::string_view CAMERA_ATTR_SHUTTER_STATE{"SHUTTER_STATE"};
static constexpr std::string_view CAMERA_ATTR_CCDDIM{"CCDDIM"};
static constexpr std::string_view CAMERA_ATTR_CAMLINK_SETUP{"CAMLINK_SETUP"};
static constexpr std::string_view CAMERA_CMD_START_EXP{"START_EXP"};
static constexpr std::string_view CAMERA_CMD_STOP_EXP{"STOP_EXP"};
@ -49,20 +53,39 @@ public:
~RaptorEagleCCD();
private:
typedef std::vector<char> byte_seq_t;
std::string _epixFmtVideoFilename;
int _cameraUnitmap;
// CameraLink read/write setup flags
uint8_t _clCommandAckBit;
uint8_t _clChecksumBit;
// attributes inner variables
double _expTime;
size_t _frameNumbers;
void initAttrComm();
void initCamera(int unitmap);
void initCamera(int unitmap = 1);
void openPIXCI();
void closePIXCI();
// CameraLink-related low-level methods
size_t clRead(byte_seq_t& bytes);
size_t clReadAndCheckAck(byte_seq_t& bytes);
size_t clWrite(const byte_seq_t& bytes);
// logging helper methods
template <bool NOEXCEPT = false>
void xclibApiCall(int err, const adc::traits::adc_input_char_range auto& func_name)
{
if (err) {
if (err < 0) {
if (std::ranges::size(func_name)) {
logError("XCLIB API call ('{}') returns: {} ({})", func_name, err, pxd_mesgErrorCode(err));
} else {

View File

@ -3,7 +3,9 @@
#include <xcliball.h>
#include <system_error>
enum class RaptorEagleCCDError : int { ERROR_OK, ERROR_INVALID_UNITMAP };
#include "raptor_eagle_cameralink.h"
enum class RaptorEagleCCDError : int { ERROR_OK, ERROR_INVALID_UNITMAP, ERROR_INVALID_ATTR_VALUE, ERROR_CAMLINK_WRITE };
namespace std
@ -33,6 +35,10 @@ struct RaptorEagleCCDErrorCategory : std::error_category {
return "OK";
case RaptorEagleCCDError::ERROR_INVALID_UNITMAP:
return "invalid EPIX-library unitmap";
case RaptorEagleCCDError::ERROR_INVALID_ATTR_VALUE:
return "invalid camera attribute value";
case RaptorEagleCCDError::ERROR_CAMLINK_WRITE:
return "not all data were transmitted via CameraLink connection";
default:
return "UNKNOWN ERROR";
}
@ -46,6 +52,44 @@ struct RaptorEagleCCDErrorCategory : std::error_category {
};
/* Error category for XCLIB errors */
struct RaptorEagleControllerErrorCategory : std::error_category {
RaptorEagleControllerErrorCategory() : std::error_category() {}
const char* name() const noexcept
{
return "EAGLE_CCD_CONTROLLER_ERROR_CATEGORY";
}
std::string message(int ec) const
{
switch (ec) {
case CL_ETX:
return "controller OK";
case CL_ETX_SER_TIMEOUT:
return "partial controller command received (camera timed out)";
case CL_ETX_CK_SUM_ERR:
return "controller command checksum mismatch";
case CL_ETX_I2C_ERR:
return "controller I2C internal failure";
case CL_ETX_UNKNOWN_CMD:
return "controller unknown command";
case CL_ETX_DONE_LOW:
return "controller EPROM is busy (FPGA reboot)";
default:
return "UNKNOWN ERROR";
}
}
static const RaptorEagleControllerErrorCategory& get()
{
static const RaptorEagleControllerErrorCategory constInst;
return constInst;
}
};
/* Error category for XCLIB errors */
struct XCLIBErrorCategory : std::error_category {
XCLIBErrorCategory() : std::error_category() {}