260 lines
7.8 KiB
C++
260 lines
7.8 KiB
C++
#include <xcliball.h>
|
|
#include <cstring>
|
|
|
|
#include "raptor_eagle_cameralink.h"
|
|
#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"
|
|
|
|
/* CONSTRUCTORS AND DESTRUCTOR */
|
|
|
|
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),
|
|
_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");
|
|
|
|
std::ranges::copy(epix_video_fmt_filename, std::back_inserter(_epixFmtVideoFilename));
|
|
|
|
logDebug("CTOR: Create RaptorEagleCCD class instance");
|
|
if (_epixFmtVideoFilename.empty()) {
|
|
logDebug("Video format filename is not set! Use of default: {}", DEFAULT_EPIX_VIDEO_FMT_FILE);
|
|
} else {
|
|
logDebug("Set video format filename: {}", _epixFmtVideoFilename);
|
|
}
|
|
}
|
|
|
|
|
|
RaptorEagleCCD::RaptorEagleCCD(std::shared_ptr<spdlog::logger> logger)
|
|
: RaptorEagleCCD(std::string_view(), std::move(logger))
|
|
{
|
|
}
|
|
|
|
|
|
RaptorEagleCCD::~RaptorEagleCCD()
|
|
{
|
|
logDebug("DTOR: Delete RaptorEagleCCD class instance");
|
|
}
|
|
|
|
|
|
/* PRIVATE METHODS */
|
|
|
|
void RaptorEagleCCD::initCamera(int unitmap)
|
|
{
|
|
logInfo("Try to init camera with unitmap: {} ...", unitmap);
|
|
|
|
if (unitmap < 0) {
|
|
throw std::system_error(RaptorEagleCCDError::ERROR_INVALID_UNITMAP);
|
|
}
|
|
|
|
_cameraUnitmap = unitmap;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
void RaptorEagleCCD::openPIXCI()
|
|
{
|
|
if (_epixFmtVideoFilename.size()) {
|
|
xclibApiCall(pxd_PIXCIopen("", nullptr, _epixFmtVideoFilename.c_str()),
|
|
std::format("pxd_PIXCIopen(\"\", NULL, {})", _epixFmtVideoFilename));
|
|
} 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
|
|
pxd_videoFormatAsIncludedInit(0);
|
|
xclibApiCall(pxd_videoFormatAsIncluded(0), "pxd_videoFormatAsIncluded(0)");
|
|
}
|
|
}
|
|
|
|
|
|
void RaptorEagleCCD::closePIXCI()
|
|
{
|
|
// no exception here!!!
|
|
xclibApiCall<true>(pxd_PIXCIclose(), "pxd_PIXCIclose()");
|
|
}
|
|
|
|
|
|
/* 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()
|
|
{
|
|
/* 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);
|
|
});
|
|
}
|