393 lines
16 KiB
C++
393 lines
16 KiB
C++
#pragma once
|
|
|
|
#include <queue>
|
|
#include <set>
|
|
#ifdef USE_SPDLOG_LIBRARY
|
|
#include <spdlog/sinks/null_sink.h>
|
|
#endif
|
|
|
|
#include <common/adc_spdlog.h>
|
|
#include <device/adc_device.h>
|
|
#include <device/adc_device_attribute.h>
|
|
#include <device/adc_device_command.h>
|
|
|
|
#include <xcliball.h>
|
|
#include <future>
|
|
#include <list>
|
|
|
|
#include "raptor_eagle_exception.h"
|
|
|
|
|
|
class RaptorEagleCCD : public adc::AdcGenericDevice<std::string,
|
|
adc::AdcDeviceAttribute<std::string_view>,
|
|
adc::AdcDeviceCommand<std::string_view>>,
|
|
public adc::AdcSpdlogLogger
|
|
{
|
|
typedef adc::AdcGenericDevice<std::string,
|
|
adc::AdcDeviceAttribute<std::string_view>,
|
|
adc::AdcDeviceCommand<std::string_view>>
|
|
base_t;
|
|
|
|
public:
|
|
/* class constants */
|
|
|
|
// separator char sequence of serialized representation of user FITS keywords array
|
|
static constexpr std::string_view USER_FITS_KEY_SEP_SEQ{"\t"};
|
|
|
|
static constexpr size_t DEFAULT_ACQ_RING_BUFFER_SIZE = 3;
|
|
static constexpr size_t DEFAULT_ACQ_RING_BUFFER_MAX_SIZE = 100;
|
|
|
|
/* some Eagle V camera constants */
|
|
// static constexpr double EAGLE_CAMERA_MAX_EXPTIME = 27487.7906944; // in seconds (0xFFFFFFFFFF * 25nsec)
|
|
static constexpr double EAGLE_CAMERA_MAX_EXPTIME = 2.5E-8 * 0xFFFFFFFFFF; // in seconds (0xFFFFFFFFFF * 25nsec)
|
|
static constexpr size_t EAGLE_CAMERA_MAX_FRAMERATE = 0xFFFFFFFFFF * 40; // in MHz (0xFFFFFFFFFF * 40MHz)
|
|
|
|
static constexpr uint16_t EAGLE_CAMERA_CCDDIM[] = {2048, 2048};
|
|
static constexpr uchar EAGLE_CAMERA_MAX_XBIN[] = {32, 64};
|
|
static constexpr uchar EAGLE_CAMERA_MAX_YBIN[] = {32, 64};
|
|
|
|
static constexpr double ADC_CALIBRATION_POINT_1 = 0.0;
|
|
static constexpr double ADC_CALIBRATION_POINT_2 = 40.0;
|
|
|
|
static constexpr double DAC_CALIBRATION_POINT_1 = 0.0;
|
|
static constexpr double DAC_CALIBRATION_POINT_2 = 40.0;
|
|
|
|
static constexpr double SHUTTER_DELAY_PERIOD = 1.6384; // in millisecs
|
|
static constexpr double SHUTTER_MAX_DELAY_PERIOD = SHUTTER_DELAY_PERIOD * 0xFF; // in millisecs
|
|
static constexpr double SHUTTER_DEFAULT_DELAY_PERIOD = 19.66; // in millisecs
|
|
|
|
static constexpr std::chrono::milliseconds MICRO_RESET_TIME_CONSTANT{100};
|
|
// microcontroller reset timeout
|
|
// NOTE: the timeout must not be lesser then ~100msecs duration of reset process
|
|
// (see instruction manual rev 1.1)
|
|
static constexpr std::chrono::milliseconds MICRO_RESET_DEFAULT_TIMEOUT{MICRO_RESET_TIME_CONSTANT +
|
|
std::chrono::milliseconds(100)};
|
|
|
|
static constexpr std::chrono::milliseconds FPGA_RESET_TIME_CONSTANT{500};
|
|
// FPGA reset timeout
|
|
// NOTE: the timeout must not be lesser then ~500msecs duration of reset process
|
|
// (see instruction manual rev 1.1)
|
|
static constexpr std::chrono::milliseconds FPGA_RESET_DEFAULT_TIMEOUT{FPGA_RESET_TIME_CONSTANT +
|
|
std::chrono::milliseconds(1000)};
|
|
|
|
|
|
// additive constant to timeout for capture process (see pxd_doSnap XCLIB function)
|
|
// this constant will be added to exposure to compute actual timeout
|
|
static constexpr std::chrono::milliseconds CAMERA_CAPTURE_TIMEOUT_ADD_CONSTANT{240000}; // 4 mins
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_XBIN{"XBIN"};
|
|
static constexpr std::string_view CAMERA_ATTR_YBIN{"YBIN"};
|
|
static constexpr std::string_view CAMERA_ATTR_ROI_STARTX{"ROI_STARTX"};
|
|
static constexpr std::string_view CAMERA_ATTR_ROI_STARTY{"ROI_STARTY"};
|
|
static constexpr std::string_view CAMERA_ATTR_ROI_WIDTH{"ROI_WIDTH"};
|
|
static constexpr std::string_view CAMERA_ATTR_ROI_HEIGHT{"ROI_HEIGHT"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_GAIN{"GAIN"};
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE{"TRIGGER_MODE"};
|
|
static constexpr std::string_view CAMERA_ATTR_READ_RATE{"READ_RATE"};
|
|
static constexpr std::string_view CAMERA_ATTR_READ_MODE{"READ_MODE"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_TECPOINT{"TECPOINT"};
|
|
static constexpr std::string_view CAMERA_ATTR_TECSTATE{"TECSTATE"};
|
|
static constexpr std::string_view CAMERA_ATTR_TECPOINT_DAC{"TECPOINT_DAC"};
|
|
static constexpr std::string_view CAMERA_ATTR_CCD_TEMP{"CCD_TEMP"};
|
|
static constexpr std::string_view CAMERA_ATTR_PCB_TEMP{"PCB_TEMP"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_EXPTIME{"EXPTIME"};
|
|
static constexpr std::string_view CAMERA_ATTR_FRAME_RATE{"FRAME_RATE"};
|
|
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_SHUTTER_OPENDELAY{"SHUTTER_OPEN_DELAY"};
|
|
static constexpr std::string_view CAMERA_ATTR_SHUTTER_CLOSEDELAY{"SHUTTER_CLOSE_DELAY"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_FITS_FILENAME{"FITS_FILENAME"};
|
|
static constexpr std::string_view CAMERA_ATTR_FITS_TEMPLATE{"FITS_TEMPLATE"};
|
|
static constexpr std::string_view CAMERA_ATTR_PERM_KEYW{"PERM_FITS_KEY"};
|
|
static constexpr std::string_view CAMERA_ATTR_CURR_KEYW{"CURR_FITS_KEY"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS{"CAMERA_STATUS"};
|
|
|
|
static constexpr std::string_view CAMERA_CMD_INITCAM{"INITCAM"};
|
|
static constexpr std::string_view CAMERA_CMD_START_EXP{"STARTEXP"};
|
|
static constexpr std::string_view CAMERA_CMD_STOP_EXP{"STOPEXP"};
|
|
static constexpr std::string_view CAMERA_CMD_ABORT_EXP{"ABORTEXP"};
|
|
static constexpr std::string_view CAMERA_CMD_CLEAR_PERM_KEYW{"CLEAR_PERM_FITS_KEYW"};
|
|
static constexpr std::string_view CAMERA_CMD_CLEAR_CURR_KEYW{"CLEAR_CURR_FITS_KEYW"};
|
|
static constexpr std::string_view CAMERA_CMD_START_RESET_MICRO{"RESET_MICRO"};
|
|
static constexpr std::string_view CAMERA_CMD_START_RESET_FPGA{"RESET_FPGA"};
|
|
|
|
// some character attributes values
|
|
static constexpr std::string_view CAMERA_ATTR_STR_INVALID{"INVALID"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_READ_MODE_NORMAL{"NORMAL"};
|
|
static constexpr std::string_view CAMERA_ATTR_READ_MODE_TEST{"TEST"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_READ_RATE_SLOW{"SLOW"};
|
|
static constexpr std::string_view CAMERA_ATTR_READ_RATE_FAST{"FAST"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_TECSTATE_ON{"ON"};
|
|
static constexpr std::string_view CAMERA_ATTR_TECSTATE_OFF{"OFF"};
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_SHUTTER_STATE_OPEN{"OPEN"}; // always open
|
|
static constexpr std::string_view CAMERA_ATTR_SHUTTER_STATE_CLOSED{"CLOSED"}; // always closed
|
|
static constexpr std::string_view CAMERA_ATTR_SHUTTER_STATE_EXP{"EXP"}; // open during acquisition
|
|
|
|
static constexpr std::string_view CAMERA_ATTR_GAIN_HIGH{"HIGH"};
|
|
static constexpr std::string_view CAMERA_ATTR_GAIN_LOW{"LOW"};
|
|
|
|
// external trigger, rising edge enabled
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_EXT_RISING{"EXTERNAL_RISING"};
|
|
// external trigger, falling edge enabled
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_EXT_FALLING{"EXTERNAL_FALLING"};
|
|
// internal trigger for continuos acquisition
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_ITR{"ITR"};
|
|
// fixed frame rate acquisition
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_FFR{"FFR"};
|
|
// snapshot
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_SNAPSHOT{"SNAPSHOT"};
|
|
// idle
|
|
static constexpr std::string_view CAMERA_ATTR_TRIGGER_MODE_IDLE{"IDLE"};
|
|
|
|
|
|
// camera status
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_IDLE{"IDLE"};
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_ARMED{"ARMED"};
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_ACQ{"ACQ"}; // camera is acquiring
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_READ{"READING"}; // camera is reading from CCD
|
|
static constexpr std::string_view CAMERA_ATTR_CAMERA_STATUS_SAVE{"SAVING"}; // camera is saving to FITS file
|
|
|
|
|
|
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_NULL_LOGGER"));
|
|
|
|
RaptorEagleCCD(std::shared_ptr<spdlog::logger> logger = spdlog::null_logger_mt("EAGLE_CCD_NULL_LOGGER"));
|
|
|
|
~RaptorEagleCCD();
|
|
|
|
|
|
private:
|
|
typedef std::vector<unsigned char> byte_seq_t;
|
|
|
|
struct acq_params_t {
|
|
std::chrono::utc_clock::time_point startTime;
|
|
std::chrono::utc_clock::time_point abortTime;
|
|
bool saveInAbort;
|
|
|
|
double expTime; // in seconds
|
|
|
|
uint16_t roiStartX;
|
|
uint16_t roiStartY;
|
|
uint16_t roiWidth;
|
|
uint16_t roiHeight;
|
|
uint8_t binX;
|
|
uint8_t binY;
|
|
|
|
std::string_view shutterState;
|
|
std::string_view readRate;
|
|
std::string_view readMode;
|
|
std::string_view gain;
|
|
|
|
double ccdTemp;
|
|
double tecSetPoint;
|
|
bool tecState;
|
|
double pcbTemp;
|
|
|
|
std::string filename;
|
|
std::string templateFilename;
|
|
std::vector<std::string> permanentKeywords;
|
|
std::vector<std::string> currentKeywords;
|
|
|
|
// std::unique_ptr<ushort> imageBuffer;
|
|
// size_t imageBufferSize;
|
|
// size_t imageBufferRows;
|
|
ushort* imageBufferPtr;
|
|
};
|
|
|
|
class AcquisitionProcess : public std::enable_shared_from_this<AcquisitionProcess>
|
|
{
|
|
friend class RaptorEagleCCD;
|
|
|
|
public:
|
|
AcquisitionProcess();
|
|
~AcquisitionProcess();
|
|
|
|
void start(const std::shared_ptr<acq_params_t>& params); // asynchronous method!
|
|
void stop(bool save = true);
|
|
std::string status();
|
|
|
|
// static std::string acqProcStatus();
|
|
private:
|
|
inline static RaptorEagleCCD* serverPtr = nullptr;
|
|
|
|
inline static std::atomic_bool isAcqInProgress = false;
|
|
|
|
inline static std::set<std::shared_ptr<AcquisitionProcess>> acqProcSptr{};
|
|
|
|
std::shared_ptr<acq_params_t> _acqParams{};
|
|
|
|
enum int8_t { STATUS_IDLE, STATUS_ACQ, STATUS_READ, STATUS_SAVE };
|
|
std::atomic_int8_t _status = STATUS_IDLE;
|
|
std::mutex _statusMutex;
|
|
};
|
|
|
|
std::string _epixFmtVideoFilename;
|
|
int _cameraUnitmap;
|
|
|
|
uint16_t _dimCCD[2] = {2048, 2048}; // init to E2V 4240 CCD dimension
|
|
int _bitsPerPixel = 16; // init to E2V 4240 CCD
|
|
int _imageFrameBuffNumber = 1;
|
|
|
|
// CCD temperature and TEC set point calibration relation coefficients
|
|
double _adcCCDTempCalibCoeffs[2] = {0, 0}; // [k, b], Temp(degs C) = k*ADC + b
|
|
|
|
// [k, b, k_rev, b_rev]
|
|
// Temp = k*DAC + b
|
|
// DAC = k_rev*Temp + b_rev
|
|
double _dacTECSetPointCalibCoeffs[4] = {0, 0};
|
|
|
|
// CameraLink read/write setup flags
|
|
uint8_t _clCommandAckBit;
|
|
uint8_t _clChecksumBit;
|
|
|
|
std::recursive_mutex _camlinkMutex;
|
|
|
|
// attributes inner variables
|
|
std::atomic_size_t _frameNumbers;
|
|
std::string _currentFitsFile; // current acquisition FITS filename
|
|
std::string _currentTemplateFile; // CFITSIO template filename
|
|
std::vector<std::string> _currentFitsKeywords{}; // current acquisition FITS keywords
|
|
std::vector<std::string> _permanentFitsKeywords{}; // permanent user FITS keywords
|
|
|
|
std::vector<std::unique_ptr<ushort[]>> _acqRingBuffer{};
|
|
std::queue<ushort*> _acqRingFreeBufferPtrs{};
|
|
|
|
|
|
// hardware version info
|
|
byte_seq_t _microVersion; // microcontroller version: _microVersion[0] - major, _microVersion[1] - minor
|
|
byte_seq_t _FPGAVersion; // same for FPGA version
|
|
|
|
// man data is 18-byte array + 2 possible bytes (ETX and checksum)
|
|
byte_seq_t _manufacturerData = byte_seq_t(20);
|
|
// extract fields according to instruction manual (WARNING: works only for little-endian platforms!)
|
|
const uint16_t& _cameraSerialNumber{
|
|
*reinterpret_cast<const uint16_t*>(_manufacturerData.data())}; // camera serial number (the first 2 bytes)
|
|
std::chrono::year_month_day _buildDate; // 3 bytes
|
|
const std::string_view _buildCode{reinterpret_cast<const char*>(_manufacturerData.data() + 5), 5}; // 5 bytes
|
|
// must be interpretated as 2-element array of calibration points [at 0C, at +40C] (4 bytes)
|
|
const uint16_t* _adcCCDTempCalibData{reinterpret_cast<const uint16_t*>(_manufacturerData.data() + 10)};
|
|
// must be interpretated as 2-element array of calibration points [at 0C, at +40C] (4 bytes)
|
|
const uint16_t* _dacTECSetPointCalibData{reinterpret_cast<const uint16_t*>(_manufacturerData.data() + 14)};
|
|
|
|
|
|
// acquisition process members
|
|
std::mutex _acqProcessesMutex;
|
|
// std::list<std::weak_ptr<AcquisitionProcess>> _acqProcesses{};
|
|
|
|
// std::future<void> _doSnapAndCopyFuture;
|
|
// std::future<void> _saveFitsFile;
|
|
// std::atomic_bool _isAcqInProgress;
|
|
|
|
void initAttrComm();
|
|
|
|
bool 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 clReadAndCheckAck();
|
|
|
|
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);
|
|
|
|
|
|
// camera and FPGA control registers getter/setter
|
|
|
|
std::bitset<8> getSystemState();
|
|
void setSystemState(const std::bitset<8>& bits);
|
|
void setSystemStateBit(const size_t bit_pos);
|
|
void clearSystemStateBit(const size_t bit_pos);
|
|
void flipSystemStateBit(const size_t bit_pos);
|
|
|
|
std::bitset<8> getFPGAState();
|
|
void setFPGAState(const std::bitset<8>& bits);
|
|
void setFPGAStateBit(const size_t bit_pos);
|
|
void clearFPGAStateBit(const size_t bit_pos);
|
|
void flipFPGAStateBit(const size_t bit_pos);
|
|
|
|
// set 'Abort' bit in trigger register
|
|
std::bitset<8> getTriggerRegister();
|
|
std::chrono::utc_clock::time_point setTriggerRegister(const std::bitset<8> bits);
|
|
std::chrono::utc_clock::time_point setTriggerRegisterBit(const size_t bit_pos);
|
|
std::chrono::utc_clock::time_point clearTriggerRegisterBit(const size_t bit_pos);
|
|
std::chrono::utc_clock::time_point flipTriggerRegisterBit(const size_t bit_pos);
|
|
|
|
// reset hardware methods
|
|
|
|
// returns true if OK, false - timeout
|
|
bool resetMicro(const std::chrono::milliseconds& timeout = MICRO_RESET_DEFAULT_TIMEOUT);
|
|
bool resetFPGA(const std::chrono::milliseconds& timeout = FPGA_RESET_DEFAULT_TIMEOUT);
|
|
|
|
// hardware info methods
|
|
|
|
void getHardwareInfo();
|
|
void getMicroVersion();
|
|
void getFPGAVersion();
|
|
|
|
// acquisition process methods
|
|
void startAquisition();
|
|
void stopAcquisition(bool save_acq);
|
|
|
|
// logging helper methods
|
|
|
|
template <bool NOEXCEPT = false>
|
|
void xclibApiCall(int err,
|
|
const adc::traits::adc_input_char_range auto& func_name,
|
|
loglevel_t log_level = spdlog::level::debug)
|
|
{
|
|
if (err < 0) {
|
|
auto s_err = pxd_mesgErrorCode(err);
|
|
|
|
if (std::ranges::size(func_name)) {
|
|
logError("XCLIB API call ('{}') returns: {} ({})", func_name, err, s_err);
|
|
} else {
|
|
logError("XCLIB API call returns: {} ({})", err, s_err);
|
|
}
|
|
|
|
if constexpr (!NOEXCEPT) {
|
|
throw std::system_error(err, XCLIBErrorCategory::get());
|
|
}
|
|
} else {
|
|
if (std::ranges::size(func_name)) {
|
|
// logDebug("XCLIB API call ('{}') finished successfully (exitcode = {})", func_name, err);
|
|
logMessage(log_level, "XCLIB API call ('{}') finished successfully (exitcode = {})", func_name, err);
|
|
} else {
|
|
// logDebug("XCLIB API call finished successfully (exitcode = {})", err);
|
|
logMessage(log_level, "XCLIB API call finished successfully (exitcode = {})", err);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <bool NOEXCEPT = false>
|
|
void xclibApiCall(int err, loglevel_t log_level = spdlog::level::debug)
|
|
{
|
|
xclibApiCall<NOEXCEPT>(err, std::string_view(""), log_level);
|
|
}
|
|
};
|