From fd8c2c79960e2c1e059b03d5f3b3386c5a7d33a0 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Fri, 6 Dec 2024 18:44:21 +0300 Subject: [PATCH] ... --- raptor_eagle_ccd.cpp | 160 +++++++++++++++++++++++++++++++++++++-- raptor_eagle_ccd.h | 32 ++++++-- raptor_eagle_exception.h | 16 +++- 3 files changed, 194 insertions(+), 14 deletions(-) diff --git a/raptor_eagle_ccd.cpp b/raptor_eagle_ccd.cpp index 751567d..60f29e4 100644 --- a/raptor_eagle_ccd.cpp +++ b/raptor_eagle_ccd.cpp @@ -131,10 +131,14 @@ RaptorEagleCCD::RaptorEagleCCD(const adc::traits::adc_input_char_range auto& epi logDebug("CTOR: Create RaptorEagleCCD class instance"); if (_epixFmtVideoFilename.empty()) { - logDebug("Video format filename is not set! Use of default: {}", DEFAULT_EPIX_VIDEO_FMT_FILE); + logInfo("Video format filename is not given! Use of default: {}", DEFAULT_EPIX_VIDEO_FMT_FILE); } else { - logDebug("Set video format filename: {}", _epixFmtVideoFilename); + logInfo("Set video format filename: {}", _epixFmtVideoFilename); } + + initAttrComm(); + + openPIXCI(); } @@ -146,6 +150,8 @@ RaptorEagleCCD::RaptorEagleCCD(std::shared_ptr logger) RaptorEagleCCD::~RaptorEagleCCD() { + closePIXCI(); + logDebug("DTOR: Delete RaptorEagleCCD class instance"); } @@ -300,7 +306,7 @@ void RaptorEagleCCD::flipFPGAStateBit(const size_t pos) /* PRIVATE METHODS */ -void RaptorEagleCCD::initCamera(int unitmap) +bool RaptorEagleCCD::initCamera(int unitmap) { logInfo("Try to init camera with unitmap: {} ...", unitmap); @@ -316,6 +322,18 @@ void RaptorEagleCCD::initCamera(int unitmap) std::format("pxd_serialConfigure({}, 0, {}, {}, 0, {}, 0, 0, 0)", _cameraUnitmap, CL_DEFAULT_BAUD_RATE, CL_DEFAULT_DATA_BITS, CL_DEFAULT_STOP_BIT)); + bool ok = resetMicro(); + if (!ok) { + logError("Cannot reset microcontroller!"); + return ok; + } + + ok = resetFPGA(); + if (!ok) { + logError("Cannot reboot FPGA!"); + return ok; + } + getSystemState(); getHardwareInfo(); @@ -323,11 +341,15 @@ void RaptorEagleCCD::initCamera(int unitmap) getFPGAVersion(); logInfo("Camera with unitmap '{}' is initialized", _cameraUnitmap); + + return true; } void RaptorEagleCCD::openPIXCI() { + logDebug("Initialize EPIX library and camera system device ..."); + if (_epixFmtVideoFilename.size()) { xclibApiCall(pxd_PIXCIopen("", nullptr, _epixFmtVideoFilename.c_str()), std::format("pxd_PIXCIopen(\"\", NULL, {})", _epixFmtVideoFilename)); @@ -343,6 +365,8 @@ void RaptorEagleCCD::openPIXCI() void RaptorEagleCCD::closePIXCI() { + logDebug("Close EPIX library and camera system device ..."); + // no exception here!!! xclibApiCall(pxd_PIXCIclose(), "pxd_PIXCIclose()"); } @@ -549,8 +573,18 @@ bool RaptorEagleCCD::resetMicro(const std::chrono::milliseconds& timeout) { std::lock_guard lock_guard(_camlinkMutex); + std::chrono::milliseconds tm = timeout; + if (tm < MICRO_RESET_TIME_CONSTANT) { // must be greater than ~100ms + logWarn("Microcontroller reset timeout must be greater than {}", MICRO_RESET_TIME_CONSTANT); + logWarn("Use of default value {}", MICRO_RESET_DEFAULT_TIMEOUT); + + tm = std::chrono::milliseconds(MICRO_RESET_DEFAULT_TIMEOUT); + } + byte_seq_t ack; - std::chrono::milliseconds sleep_dur = timeout.count() < 10 ? timeout : std::chrono::milliseconds(10); + std::chrono::milliseconds::rep cnt = (tm - MICRO_RESET_TIME_CONSTANT).count(); + std::chrono::milliseconds sleep_dur = + cnt > 10 ? std::chrono::milliseconds(cnt / 10) : std::chrono::milliseconds(10); uint8_t cksum_old = _clChecksumBit; _clChecksumBit = 1; // to compute mandatory checksum in clWrite below! @@ -565,12 +599,58 @@ bool RaptorEagleCCD::resetMicro(const std::chrono::milliseconds& timeout) // poll controller auto start = std::chrono::steady_clock::now(); do { - clWrite({0x4F, 0x51}); + // poll camera with 'set-system-status' + // clWrite({0x4F, 0x51}); + clWrite({0x4F, 0x50}); std::this_thread::sleep_for(sleep_dur); clRead(ack); - if (ack[0] == CL_ETX) + if (ack[0] == CL_ETX) { + logInfo("Camera microcontroller is reset successfully!"); return true; + } + + } while ((std::chrono::steady_clock::now() - start) < timeout); + + return false; +} + + +bool RaptorEagleCCD::resetFPGA(const std::chrono::milliseconds& timeout) +{ + std::lock_guard lock_guard(_camlinkMutex); + + std::chrono::milliseconds tm = timeout; + if (tm < FPGA_RESET_TIME_CONSTANT) { // must be greater than ~100ms + logWarn("FPGA reset timeout must be greater than {} millisecs", FPGA_RESET_TIME_CONSTANT.count()); + logWarn("Use of default value {}", FPGA_RESET_DEFAULT_TIMEOUT); + + tm = std::chrono::milliseconds(FPGA_RESET_DEFAULT_TIMEOUT); + } + + byte_seq_t ack; + std::chrono::milliseconds::rep cnt = (tm - FPGA_RESET_TIME_CONSTANT).count(); + std::chrono::milliseconds sleep_dur = + cnt > 10 ? std::chrono::milliseconds(cnt / 10) : std::chrono::milliseconds(10); + + clearSystemStateBit(CL_SYSTEM_STATUS_FPGA_RST_HOLD_BIT); // set bit to 0 to hold FPGA in reset state + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + setSystemStateBit(CL_SYSTEM_STATUS_FPGA_RST_HOLD_BIT); // set bit to 1 to boot FPGA + + // according to instruction manual rev 1.1 FPGA will take approximately 500msecs to reset + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + // poll controller + auto start = std::chrono::steady_clock::now(); + do { + clWrite({0x4F, 0x52}); + std::this_thread::sleep_for(sleep_dur); + clRead(ack); + + if (ack[0] == CL_ETX) { + logInfo("Camera FPGA is reset successfully!"); + return true; + } } while ((std::chrono::steady_clock::now() - start) < timeout); @@ -584,6 +664,9 @@ void RaptorEagleCCD::getHardwareInfo() { std::lock_guard lock_guard(_camlinkMutex); + logDebug("Try to get manufacturer EPROM data ..."); + + // first, according to instruction manual, set FPGA comms bit setSystemStateBit(CL_SYSTEM_STATUS_FPGA_EEPROM_COMMS_BIT); @@ -630,6 +713,8 @@ void RaptorEagleCCD::getHardwareInfo() logDebug("Computed DAC-to-Temp linear relation: DAC(counts) = {}*Temp(C)+{}"); logDebug("---------------------------------"); + + clearSystemStateBit(CL_SYSTEM_STATUS_FPGA_EEPROM_COMMS_BIT); } @@ -638,8 +723,12 @@ void RaptorEagleCCD::getMicroVersion() { std::lock_guard lock_guard(_camlinkMutex); + logDebug("Try to get microcontroller version ..."); + clWrite({0x56}); clReadAndCheckAck(_microVersion); + + logDebug("Microcontroller version: {}.{}", _microVersion[0], _microVersion[1]); } @@ -647,7 +736,11 @@ void RaptorEagleCCD::getFPGAVersion() { std::lock_guard lock_guard(_camlinkMutex); + logDebug("Try to get FPGA version ..."); + _FPGAVersion = readRegisters({0x7E, 0x7F}); + + logDebug("FPGA version: {}.{}", _FPGAVersion[0], _FPGAVersion[1]); } @@ -656,6 +749,8 @@ void RaptorEagleCCD::getFPGAVersion() void RaptorEagleCCD::initAttrComm() { + logDebug("Try to create attributes and commands ..."); + // helper to setup 8-bit register attributes // 'validator' is a callable with signature: std::pair validator(const uchar&) auto create8BitAttr = [this](attr_ident_t name, auto reg_addr, auto&& validator, std::string_view log_mark) { @@ -737,15 +832,64 @@ void RaptorEagleCCD::initAttrComm() addCommand(CAMERA_CMD_CLEAR_PERM_KEYW, [this]() { + logDebug("Try to execute '{}' command", CAMERA_CMD_CLEAR_PERM_KEYW); auto N = _permanentFitsKeywords.size(); _permanentFitsKeywords.clear(); logInfo("Permanent FITS keywords are deleted! ({} keywords were cleared)", N); }); + addCommand(CAMERA_CMD_START_RESET_MICRO, [this]() { + logDebug("Try to execute '{}' command", CAMERA_CMD_START_RESET_MICRO); + if (resetMicro()) + return; + + throw std::error_code(RaptorEagleCCDError::ERROR_CANNOT_RESET_MICRO); + }); + + + addCommand(CAMERA_CMD_START_RESET_FPGA, [this]() { + logDebug("Try to execute '{}' command", CAMERA_CMD_START_RESET_FPGA); + if (resetFPGA()) + return; + + throw std::error_code(RaptorEagleCCDError::ERROR_CANNOT_RESET_FPGA); + }); + + + /* ------- ATTRIBUTES ------- */ - /* PERMANENT AND CURRENT USER FITS KEYWORDS */ + /* CURRENT FITS IMAGE FILENAME AND ITS HEADER TEMPLATE, PERMANENT AND CURRENT USER FITS KEYWORDS */ + + addAttribute( + CAMERA_ATTR_FITS_FILENAME, + [this]() { + logTrace("Return current FITS-image filename as {}", _currentFitsFile); + return _currentFitsFile; + }, + [this](const std::string& filename) { + logDebug("Set current FITS-image filename to {}", filename); + + if (filename.empty()) { + logWarn("An empty FITS filename! Acquisition process is disabled!"); + } + + _currentFitsFile = filename; + }); + + addAttribute( + CAMERA_ATTR_FITS_TEMPLATE, + [this]() { + logTrace("Return current FITS-image header template filename as {}", _currentTemplateFile); + return _currentTemplateFile; + }, + [this](const std::string& filename) { + logDebug("Set current FITS-image header template filename to {}", filename); + + _currentTemplateFile = filename; + }); + // NOTE: setter and deserializer adds keywords to the end of current array!!! addAttribute( @@ -1395,4 +1539,6 @@ void RaptorEagleCCD::initAttrComm() logDebug("Trigger mode bits are set to 0b{:08b}", bits); }); + + logDebug("Attributes and commands are successfully created!"); } diff --git a/raptor_eagle_ccd.h b/raptor_eagle_ccd.h index d253d87..6e3c0c9 100644 --- a/raptor_eagle_ccd.h +++ b/raptor_eagle_ccd.h @@ -47,6 +47,19 @@ public: 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)}; static constexpr std::string_view CAMERA_ATTR_XBIN{"XBIN"}; @@ -55,23 +68,28 @@ public: 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_CCDDIM{"CCDDIM"}; - static constexpr std::string_view CAMERA_ATTR_CAMLINK_SETUP{"CAMLINK_SETUP"}; + + 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"}; @@ -79,6 +97,8 @@ public: static constexpr std::string_view CAMERA_CMD_START_EXP{"START_EXP"}; static constexpr std::string_view CAMERA_CMD_STOP_EXP{"STOP_EXP"}; static constexpr std::string_view CAMERA_CMD_CLEAR_PERM_KEYW{"CLEAR_PERM_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"}; @@ -140,7 +160,7 @@ private: // attributes inner variables std::atomic_size_t _frameNumbers; std::string _currentFitsFile; // current acquisition FITS filename - std::vector _currentTemplateFile; // CFITSIO template filename + std::string _currentTemplateFile; // CFITSIO template filename std::vector _currentFitsKeywords; // current acquisition FITS keywords std::vector _permanentFitsKeywords; // permanent user FITS keywords @@ -163,7 +183,7 @@ private: void initAttrComm(); - void initCamera(int unitmap = 1); + bool initCamera(int unitmap = 1); void openPIXCI(); void closePIXCI(); @@ -207,8 +227,8 @@ private: // reset hardware methods // returns true if OK, false - timeout - bool resetMicro(const std::chrono::milliseconds& timeout = std::chrono::milliseconds(5000)); - + 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 diff --git a/raptor_eagle_exception.h b/raptor_eagle_exception.h index 252e75c..24c8140 100644 --- a/raptor_eagle_exception.h +++ b/raptor_eagle_exception.h @@ -5,7 +5,15 @@ #include "raptor_eagle_cameralink.h" -enum class RaptorEagleCCDError : int { ERROR_OK, ERROR_INVALID_UNITMAP, ERROR_INVALID_ATTR_VALUE, ERROR_CAMLINK_WRITE }; +enum class RaptorEagleCCDError : int { + ERROR_OK, + ERROR_INVALID_UNITMAP, + ERROR_INVALID_ATTR_VALUE, + ERROR_CAMLINK_WRITE, + ERROR_CANNOT_INIT_CAMERA, + ERROR_CANNOT_RESET_MICRO, + ERROR_CANNOT_RESET_FPGA +}; namespace std @@ -39,6 +47,12 @@ struct RaptorEagleCCDErrorCategory : std::error_category { return "invalid camera attribute value"; case RaptorEagleCCDError::ERROR_CAMLINK_WRITE: return "not all data were transmitted via CameraLink connection"; + case RaptorEagleCCDError::ERROR_CANNOT_INIT_CAMERA: + return "cannot initialize camera hardware"; + case RaptorEagleCCDError::ERROR_CANNOT_RESET_MICRO: + return "cannot reset camera microcontroller"; + case RaptorEagleCCDError::ERROR_CANNOT_RESET_FPGA: + return "cannot reset FPGA board"; default: return "UNKNOWN ERROR"; }