...
This commit is contained in:
parent
db79062506
commit
2cb6cc2926
@ -1,4 +1,3 @@
|
|||||||
#include <xcliball.h>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "raptor_eagle_cameralink.h"
|
#include "raptor_eagle_cameralink.h"
|
||||||
@ -7,6 +6,62 @@
|
|||||||
|
|
||||||
#include <common/adc_utils.h>
|
#include <common/adc_utils.h>
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
|
||||||
|
// compute checksum as XOR operation along elements of byte array
|
||||||
|
template <std::ranges::input_range R>
|
||||||
|
auto computeChecksum(const R& bytes, bool final_etx = true)
|
||||||
|
requires std::convertible_to<std::ranges::range_value_t<R>, char>
|
||||||
|
{
|
||||||
|
std::ranges::range_value_t<R> res = 0;
|
||||||
|
|
||||||
|
if (std::ranges::size(bytes) == 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& byte : bytes) {
|
||||||
|
res ^= byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (final_etx) {
|
||||||
|
res ^= CL_ETX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume that least significant byte is the last one in 'bytes'
|
||||||
|
template <std::ranges::input_range R>
|
||||||
|
size_t convert40BitToCounts(const R& bytes)
|
||||||
|
requires std::same_as<std::ranges::range_value_t<R>, unsigned char>
|
||||||
|
{
|
||||||
|
size_t counts = 0, i = std::ranges::size(bytes);
|
||||||
|
|
||||||
|
for (auto& byte : bytes) {
|
||||||
|
counts += byte << (--i * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::ranges::output_range<unsigned char> R>
|
||||||
|
R convertCountsTo40Bit(uint64_t counts)
|
||||||
|
{
|
||||||
|
R res;
|
||||||
|
|
||||||
|
auto sp = std::span(reinterpret_cast<unsigned char*>(&counts), 8);
|
||||||
|
|
||||||
|
// least significant byte in the end of the output range
|
||||||
|
std::ranges::copy(sp | std::views::take(5) | std::views::reverse, std::back_inserter(res));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_EPIX_VIDEO_FMT_FILE "raptor_eagle-v.fmt"
|
#define DEFAULT_EPIX_VIDEO_FMT_FILE "raptor_eagle-v.fmt"
|
||||||
|
|
||||||
/* CONSTRUCTORS AND DESTRUCTOR */
|
/* CONSTRUCTORS AND DESTRUCTOR */
|
||||||
@ -17,8 +72,8 @@ RaptorEagleCCD::RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epi
|
|||||||
adc::AdcSpdlogLogger(logger),
|
adc::AdcSpdlogLogger(logger),
|
||||||
_epixFmtVideoFilename(),
|
_epixFmtVideoFilename(),
|
||||||
_cameraUnitmap(1), // by default only the single camera
|
_cameraUnitmap(1), // by default only the single camera
|
||||||
_clCommandAckBit(1), // enable by default
|
_clCommandAckBit(1), // enable by default (at camera boot up)
|
||||||
_clChecksumBit(1), // enable by default
|
_clChecksumBit(1), // enable by default (at camera boot up)
|
||||||
_expTime(0.0)
|
_expTime(0.0)
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -111,7 +166,7 @@ size_t RaptorEagleCCD::clRead(byte_seq_t& bytes)
|
|||||||
bytes.resize(nbytes);
|
bytes.resize(nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
xclibApiCall(pxd_serialRead(_cameraUnitmap, 0, bytes.data(), nbytes),
|
xclibApiCall(pxd_serialRead(_cameraUnitmap, 0, (char*)bytes.data(), nbytes),
|
||||||
std::format("pxd_serialRead({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), nbytes));
|
std::format("pxd_serialRead({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), nbytes));
|
||||||
|
|
||||||
|
|
||||||
@ -139,9 +194,19 @@ size_t RaptorEagleCCD::clReadAndCheckAck(byte_seq_t& bytes)
|
|||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t RaptorEagleCCD::clReadAndCheckAck()
|
||||||
|
{
|
||||||
|
byte_seq_t bytes;
|
||||||
|
|
||||||
|
return clReadAndCheckAck(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 'bytes' must contain only data without trailing ETX and checksum bytes!
|
||||||
size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
|
size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
|
||||||
{
|
{
|
||||||
|
static unsigned char etx_checksum_bytes[] = {CL_ETX, 0xFF};
|
||||||
|
|
||||||
if (bytes.empty()) {
|
if (bytes.empty()) {
|
||||||
logWarn("An empty transmitted byte sequence! Nothing to do!");
|
logWarn("An empty transmitted byte sequence! Nothing to do!");
|
||||||
return 0;
|
return 0;
|
||||||
@ -155,21 +220,23 @@ size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t nbytes, tr_nbytes = bytes.size();
|
size_t nbytes, tr_nbytes = 1 + _clChecksumBit;
|
||||||
|
|
||||||
// how many bytes are available in Tx-buffer
|
// how many bytes are available in Tx-buffer
|
||||||
xclibApiCall(nbytes = pxd_serialWrite(_cameraUnitmap, 0, nullptr, 0),
|
xclibApiCall(nbytes = pxd_serialWrite(_cameraUnitmap, 0, nullptr, 0),
|
||||||
std::format("pxd_serialWrite({}, 0, NULL, 0)", _cameraUnitmap));
|
std::format("pxd_serialWrite({}, 0, NULL, 0)", _cameraUnitmap));
|
||||||
|
|
||||||
if (nbytes) {
|
if (nbytes) {
|
||||||
tr_nbytes += _clCommandAckBit + _clChecksumBit;
|
if (nbytes < (bytes.size() + tr_nbytes)) {
|
||||||
|
|
||||||
if (nbytes < tr_nbytes) {
|
|
||||||
logWarn(
|
logWarn(
|
||||||
"Not enough of available space in the internal Tx-buffer (needs = {}, available = {})! Nothing to do!",
|
"Not enough of available space in the internal Tx-buffer (needs = {}, available = {})! Nothing to do!",
|
||||||
tr_nbytes, nbytes);
|
bytes.size() + tr_nbytes, nbytes);
|
||||||
nbytes = 0;
|
nbytes = 0;
|
||||||
} else {
|
} else {
|
||||||
|
if (_clChecksumBit) {
|
||||||
|
etx_checksum_bytes[1] = details::computeChecksum(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
xclibApiCall(
|
xclibApiCall(
|
||||||
nbytes = pxd_serialWrite(_cameraUnitmap, 0, (char*)bytes.data(), bytes.size()),
|
nbytes = pxd_serialWrite(_cameraUnitmap, 0, (char*)bytes.data(), bytes.size()),
|
||||||
std::format("pxd_serialWrite({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), bytes.size()));
|
std::format("pxd_serialWrite({}, 0, {}, {})", _cameraUnitmap, (void*)bytes.data(), bytes.size()));
|
||||||
@ -177,6 +244,23 @@ size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
|
|||||||
if (nbytes != bytes.size()) {
|
if (nbytes != bytes.size()) {
|
||||||
throw std::error_code(RaptorEagleCCDError::ERROR_CAMLINK_WRITE);
|
throw std::error_code(RaptorEagleCCDError::ERROR_CAMLINK_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send trailing ETX and possible checksum bytes
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (tr_nbytes > 1) {
|
||||||
|
logDebug("Write trailing ETX and checksum bytes");
|
||||||
|
} else {
|
||||||
|
logDebug("Write trailing ETX byte");
|
||||||
|
}
|
||||||
|
xclibApiCall(
|
||||||
|
n = pxd_serialWrite(_cameraUnitmap, 0, (char*)etx_checksum_bytes, tr_nbytes),
|
||||||
|
std::format("pxd_serialWrite({}, 0, {}, {})", _cameraUnitmap, (void*)etx_checksum_bytes, tr_nbytes));
|
||||||
|
if (n != tr_nbytes) {
|
||||||
|
throw std::error_code(RaptorEagleCCDError::ERROR_CAMLINK_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nbytes += n;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logWarn("No available space in the internal Tx-buffer! Nothing to do!");
|
logWarn("No available space in the internal Tx-buffer! Nothing to do!");
|
||||||
@ -186,6 +270,69 @@ size_t RaptorEagleCCD::clWrite(const byte_seq_t& bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RaptorEagleCCD::byte_seq_t RaptorEagleCCD::readRegisters(const RaptorEagleCCD::byte_seq_t& addrs,
|
||||||
|
byte_seq_t set_addr_cmd)
|
||||||
|
{
|
||||||
|
// to protect in multi-threading environment (multiple read-write operations, see below)
|
||||||
|
std::lock_guard<std::mutex> lock_guard(_camlinkMutex);
|
||||||
|
|
||||||
|
byte_seq_t reg_vals, ans(3);
|
||||||
|
|
||||||
|
if (addrs.empty()) {
|
||||||
|
logWarn("Registers addresses array is an empty! Nothing to do!");
|
||||||
|
return reg_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from Eagle V 4240 instruction manual (rev 1.1)
|
||||||
|
byte_seq_t set_addr_comm = std::move(set_addr_cmd); // set address controller command
|
||||||
|
static const byte_seq_t read_reg_comm{0x53, 0xE1, 0x01}; // read register controller command
|
||||||
|
|
||||||
|
|
||||||
|
reg_vals.resize(addrs.size());
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto& addr : addrs) {
|
||||||
|
// set address
|
||||||
|
set_addr_comm[3] = addr;
|
||||||
|
clWrite(set_addr_comm);
|
||||||
|
clReadAndCheckAck(ans);
|
||||||
|
|
||||||
|
// get value
|
||||||
|
clWrite(read_reg_comm);
|
||||||
|
clReadAndCheckAck(ans);
|
||||||
|
|
||||||
|
reg_vals[i++] = ans[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RaptorEagleCCD::writeRegisters(const byte_seq_t& addrs, const byte_seq_t& values)
|
||||||
|
{
|
||||||
|
// to protect in multi-threading environment (multiple read-write operations, see below)
|
||||||
|
std::lock_guard<std::mutex> lock_guard(_camlinkMutex);
|
||||||
|
|
||||||
|
if (addrs.empty() || values.empty()) {
|
||||||
|
logWarn("Registers addresses or values array is an empty! Nothing to do!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t N = addrs.size() < values.size() ? addrs.size() : values.size();
|
||||||
|
|
||||||
|
// from Eagle V 4240 instruction manual (rev 1.1)
|
||||||
|
byte_seq_t comm{0x53, 0xE0, 0x02, 0x00, 0x00};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
comm[3] = addrs[i];
|
||||||
|
comm[4] = values[i];
|
||||||
|
|
||||||
|
clWrite(comm);
|
||||||
|
clReadAndCheckAck(); // no data from controller here just check answer for errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* CREATE COMMANDS AND ATTRIBUTES */
|
/* CREATE COMMANDS AND ATTRIBUTES */
|
||||||
|
|
||||||
void RaptorEagleCCD::initAttrComm()
|
void RaptorEagleCCD::initAttrComm()
|
||||||
|
|||||||
@ -43,7 +43,21 @@ public:
|
|||||||
// static constexpr std::string_view CAMERA_CMD_OPEN_SHUTTER{"OPEN_SHUTTER"};
|
// static constexpr std::string_view CAMERA_CMD_OPEN_SHUTTER{"OPEN_SHUTTER"};
|
||||||
// static constexpr std::string_view CAMERA_CMD_CLOSE_SHUTTER{"CLOSE_SHUTTER"};
|
// static constexpr std::string_view CAMERA_CMD_CLOSE_SHUTTER{"CLOSE_SHUTTER"};
|
||||||
|
|
||||||
|
// system status byte bits
|
||||||
|
struct SystemStatus {
|
||||||
|
bool checkSumEnabled;
|
||||||
|
bool ackEnabled;
|
||||||
|
bool bootedFPGA;
|
||||||
|
bool holdFPGAInReset;
|
||||||
|
bool commsFPGAEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FPGA status bits
|
||||||
|
struct FPGAStatus {
|
||||||
|
bool highGainEnabled;
|
||||||
|
bool overTemp;
|
||||||
|
bool TECEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epix_video_fmt_filename,
|
RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epix_video_fmt_filename,
|
||||||
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("EAGLE_CCD_NULLLOGGER"));
|
std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("EAGLE_CCD_NULLLOGGER"));
|
||||||
@ -53,7 +67,7 @@ public:
|
|||||||
~RaptorEagleCCD();
|
~RaptorEagleCCD();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<char> byte_seq_t;
|
typedef std::vector<unsigned char> byte_seq_t;
|
||||||
|
|
||||||
std::string _epixFmtVideoFilename;
|
std::string _epixFmtVideoFilename;
|
||||||
int _cameraUnitmap;
|
int _cameraUnitmap;
|
||||||
@ -62,6 +76,8 @@ private:
|
|||||||
uint8_t _clCommandAckBit;
|
uint8_t _clCommandAckBit;
|
||||||
uint8_t _clChecksumBit;
|
uint8_t _clChecksumBit;
|
||||||
|
|
||||||
|
std::mutex _camlinkMutex;
|
||||||
|
|
||||||
// attributes inner variables
|
// attributes inner variables
|
||||||
double _expTime;
|
double _expTime;
|
||||||
size_t _frameNumbers;
|
size_t _frameNumbers;
|
||||||
@ -73,13 +89,28 @@ private:
|
|||||||
void openPIXCI();
|
void openPIXCI();
|
||||||
void closePIXCI();
|
void closePIXCI();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// CameraLink-related low-level methods
|
// CameraLink-related low-level methods
|
||||||
|
|
||||||
size_t clRead(byte_seq_t& bytes);
|
size_t clRead(byte_seq_t& bytes);
|
||||||
size_t clReadAndCheckAck(byte_seq_t& bytes);
|
size_t clReadAndCheckAck(byte_seq_t& bytes);
|
||||||
|
size_t clReadAndCheckAck();
|
||||||
|
|
||||||
size_t clWrite(const byte_seq_t& bytes);
|
size_t clWrite(const byte_seq_t& bytes);
|
||||||
|
|
||||||
|
// CameraLink-related registers read/write methods
|
||||||
|
|
||||||
|
// there are two kind of SET-READ_REGISTER-ADDRESS command in the current version of the camera controller firmware:
|
||||||
|
// {0x53, 0xE0, 0x01} and
|
||||||
|
// {0x53, 0xE0, 0x02}
|
||||||
|
//
|
||||||
|
// NOTE: given 'set_addr_cmd' byte sequence must be one-byte longer than the command itself!!!
|
||||||
|
byte_seq_t readRegisters(const byte_seq_t& addrs, byte_seq_t set_addr_cmd = {0x53, 0xE0, 0x01, 0x00});
|
||||||
|
void writeRegisters(const byte_seq_t& addrs, const byte_seq_t& values);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// logging helper methods
|
// logging helper methods
|
||||||
|
|
||||||
template <bool NOEXCEPT = false>
|
template <bool NOEXCEPT = false>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user