...
This commit is contained in:
parent
719e2ec7e7
commit
2b353ab839
@ -8,6 +8,37 @@
|
||||
/*******************************************************************************/
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
double JulianDay(const std::chrono::utc_clock::time_point& tm)
|
||||
{
|
||||
auto stp = std::chrono::time_point{std::chrono::utc_clock::to_sys(tm)};
|
||||
|
||||
const auto stp_days = std::chrono::floor<std::chrono::days>(stp);
|
||||
|
||||
const std::chrono::year_month_day ymd{stp_days};
|
||||
|
||||
int y = (int)ymd.year();
|
||||
unsigned m = (unsigned)ymd.month();
|
||||
unsigned D = (unsigned)ymd.day();
|
||||
|
||||
if (m < 3) {
|
||||
m += 12;
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
// fraction of day
|
||||
double df = std::chrono::duration<double, std::ratio<86400>>(stp - stp_days).count();
|
||||
|
||||
int C = static_cast<int>(2.0 - y / 100.0 + y / 400.0);
|
||||
int E = static_cast<int>(365.25 * (y + 4716.0)), F = static_cast<int>(30.6001 * (m + 1.0));
|
||||
|
||||
return C + D + E + F - 1524.5 + df;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
RaptorEagleCCD::AcquisitionProcess::AcquisitionProcess(RaptorEagleCCD* manager) : _manager(manager)
|
||||
{
|
||||
std::stringstream st;
|
||||
@ -26,6 +57,8 @@ RaptorEagleCCD::AcquisitionProcess::~AcquisitionProcess()
|
||||
|
||||
void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_t>& params)
|
||||
{
|
||||
isAcqInProgress = true;
|
||||
|
||||
// _acqParams = std::move(params);
|
||||
_acqParams = params;
|
||||
_acqParams->abortTime = std::chrono::utc_clock::time_point(); // to ensure the time point is in past
|
||||
@ -74,15 +107,20 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
|
||||
|
||||
isAcqInProgress = false;
|
||||
|
||||
// save to FITS file
|
||||
// ------- save to FITS file --------
|
||||
|
||||
if (_acqParams->filename.empty()) {
|
||||
_manager->logWarn("An empty FITS filename is given! Do not save acquired image!");
|
||||
return;
|
||||
}
|
||||
|
||||
_manager->logInfo("Try to save FITS file with name '{}'", _acqParams->filename);
|
||||
|
||||
fitsfile* fitsFilePtr;
|
||||
int status = 0;
|
||||
|
||||
int naxis = 2;
|
||||
long naxes[naxis];
|
||||
// int naxis = 2;
|
||||
long naxes[2];
|
||||
naxes[0] = _acqParams->roiWidth;
|
||||
naxes[1] = _acqParams->roiHeight;
|
||||
|
||||
@ -90,8 +128,99 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
|
||||
|
||||
fits_clear_errmsg();
|
||||
|
||||
_manager->logDebug("Create an empty FITS file ...");
|
||||
fits_create_file(&fitsFilePtr, _acqParams->filename.c_str(), &status);
|
||||
|
||||
_manager->logDebug("Create primary FITS HDU (dim = [{}, {}])", naxes[0], naxes[1]);
|
||||
fits_create_img(fitsFilePtr, USHORT_IMG, 2, naxes, &status);
|
||||
|
||||
_manager->logDebug("Write {} pixels to the HDU ...", npix);
|
||||
fits_write_img(fitsFilePtr, USHORT_IMG, 1, (LONGLONG)npix, _imageBuffer.get(), &status);
|
||||
|
||||
|
||||
// helper to convert std::string_view to C-lang null-terminated string
|
||||
auto sv2cstr = [](const std::string_view& sv) {
|
||||
static char buffer[72];
|
||||
size_t i = 0;
|
||||
for (const char& el : sv) {
|
||||
buffer[i++] = el;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
|
||||
return (const char*)buffer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// the hardcoded camera setup-related keywords
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "ORIGIN", "SAO RAS", NULL, &status);
|
||||
fits_update_key_str(fitsFilePtr, "CREATOR", "RaptorEagleV control software", NULL, &status);
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "FILE", _acqParams->filename.c_str(), "Original filename", &status);
|
||||
fits_write_date(fitsFilePtr, &status);
|
||||
|
||||
|
||||
std::string comm;
|
||||
std::string str = std::format("{0:%F}T{0:%H}:{0:%M}:{0:%S}", _acqParams->startTime);
|
||||
double jd = details::JulianDay(_acqParams->startTime);
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "DATE-OBS", str.c_str(), "Start of the exposure in UTC", &status);
|
||||
fits_update_key_dbl(fitsFilePtr, "JD", jd, -12, "Julian day of exposure start time", &status);
|
||||
fits_update_key_dbl(fitsFilePtr, "MJD", jd - 2400000.5, -12, "Modified Julian day of exposure start time",
|
||||
&status);
|
||||
|
||||
if (_acqParams->startTime < _acqParams->abortTime) { // acquisition was aborted
|
||||
std::chrono::duration<double> real_exp = _acqParams->abortTime - _acqParams->startTime;
|
||||
_acqParams->expTime = real_exp.count();
|
||||
}
|
||||
|
||||
fits_update_key_dbl(fitsFilePtr, "EXPTIME", _acqParams->expTime, -3, "Integration time in seconds", &status);
|
||||
|
||||
|
||||
fits_update_key_lng(fitsFilePtr, "CRPIX1", 1, "Reference pixel along X-axis", &status);
|
||||
fits_update_key_lng(fitsFilePtr, "CRVAL1", 1, "Physical value of the reference pixel", &status);
|
||||
fits_update_key_lng(fitsFilePtr, "STARTX", _acqParams->roiStartX,
|
||||
"Image area start pixel along X-axis [CCD pixel]", &status);
|
||||
|
||||
|
||||
fits_update_key_lng(fitsFilePtr, "CRPIX2", 1, "Reference pixel along Y-axis", &status);
|
||||
fits_update_key_lng(fitsFilePtr, "CRVAL2", 1, "Physical value of the reference pixel", &status);
|
||||
fits_update_key_lng(fitsFilePtr, "STARTY", _acqParams->roiStartY,
|
||||
"Image area start pixel along Y-axis [CCD pixel]", &status);
|
||||
|
||||
fits_update_key_lng(fitsFilePtr, "XBIN", _acqParams->binX, "Horizontal binning", &status);
|
||||
fits_update_key_lng(fitsFilePtr, "YBIN", _acqParams->binY, "Vertical binning", &status);
|
||||
str = std::format("{}x{}", _acqParams->binX, _acqParams->binY);
|
||||
fits_update_key_str(fitsFilePtr, "BINNING", str.c_str(), "Binning mode (XBINxYBIN)", &status);
|
||||
|
||||
comm = "Shutter state: ";
|
||||
comm += _acqParams->shutterState == CAMERA_ATTR_SHUTTER_STATE_CLOSED ? "always closed"
|
||||
: _acqParams->shutterState == CAMERA_ATTR_SHUTTER_STATE_OPEN ? "always open"
|
||||
: _acqParams->shutterState == CAMERA_ATTR_SHUTTER_STATE_EXP ? "open for exposure duration time"
|
||||
: "unknown";
|
||||
fits_update_key_str(fitsFilePtr, "SHUTTER", sv2cstr(_acqParams->shutterState), comm.c_str(), &status);
|
||||
|
||||
comm = "Camera readout rate ";
|
||||
comm += _acqParams->readRate == CAMERA_ATTR_READ_RATE_FAST ? "(2 MHz)"
|
||||
: _acqParams->readRate == CAMERA_ATTR_READ_RATE_SLOW ? "(75 kHz)"
|
||||
: "unknown";
|
||||
fits_update_key_str(fitsFilePtr, "READRATE", sv2cstr(_acqParams->readRate), comm.c_str(), &status);
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "READMODE", sv2cstr(_acqParams->readMode), "Camera readout mode", &status);
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "GAIN", sv2cstr(_acqParams->gain), "Preamp gain", &status);
|
||||
|
||||
str = _acqParams->tecState ? "ON" : "OFF";
|
||||
fits_update_key_str(fitsFilePtr, "TECSTATE", str.c_str(), "Thermoelectrical cooler state", &status);
|
||||
|
||||
fits_update_key_dbl(fitsFilePtr, "CCDTEMP", _acqParams->ccdTemp, -2, "CCD chip temperature in Celsius",
|
||||
&status);
|
||||
fits_update_key_dbl(fitsFilePtr, "PCBTEMP", _acqParams->pcbTemp, -2, "PCB temperature in Celsius", &status);
|
||||
fits_update_key_dbl(fitsFilePtr, "TECSETPT", _acqParams->tecSetPoint, -2,
|
||||
"TEC set point temperature in Celsius", &status);
|
||||
|
||||
if (!status) {
|
||||
// keywords from user template file
|
||||
if (_acqParams->templateFilename.size() && !status) {
|
||||
_manager->logDebug("Copy keywords from '{}' template file", _acqParams->templateFilename);
|
||||
@ -99,24 +228,84 @@ void RaptorEagleCCD::AcquisitionProcess::start(const std::shared_ptr<acq_params_
|
||||
if (status) { // ignore possible errors
|
||||
fits_get_errstatus(status, err_str);
|
||||
_manager->logWarn(
|
||||
"An error occured while copy keywords from the template file '{}' (err = {}, msg = {})! Ignore!",
|
||||
"An error occured while copy keywords from the template file '{}' (err = {}, msg = {})! "
|
||||
"Ignore!",
|
||||
_acqParams->templateFilename, status, err_str);
|
||||
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// the keywords
|
||||
// permanent keywords (may update keywords from template file!)
|
||||
char card[80];
|
||||
char kname[8];
|
||||
int k_type;
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "ORIGIN", "SAO RAS", NULL, &status);
|
||||
fits_update_key_str(fitsFilePtr, "CREATOR", "RaptorEagleV control software", NULL, &status);
|
||||
for (auto& s : _manager->_permanentFitsKeywords) {
|
||||
fits_parse_template(s.data(), card, &k_type, &status);
|
||||
if (status) { // ignore possible errors
|
||||
fits_get_errstatus(status, err_str);
|
||||
_manager->logWarn(
|
||||
"An error occured while writing permanent keyword card [{}] (err = {}, msg = {})! "
|
||||
"Ignore!",
|
||||
s, status, err_str);
|
||||
|
||||
status = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
kname[i] = card[i];
|
||||
}
|
||||
}
|
||||
fits_update_card(fitsFilePtr, kname, card, &status);
|
||||
}
|
||||
|
||||
// keyword from user (may update template file and permanent keywords!)
|
||||
for (auto& s : _manager->_currentFitsKeywords) {
|
||||
fits_parse_template(s.data(), card, &k_type, &status);
|
||||
if (status) { // ignore possible errors
|
||||
fits_get_errstatus(status, err_str);
|
||||
_manager->logWarn(
|
||||
"An error occured while writing user keyword card [{}] (err = {}, msg = {})! "
|
||||
"Ignore!",
|
||||
s, status, err_str);
|
||||
|
||||
status = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
kname[i] = card[i];
|
||||
}
|
||||
}
|
||||
fits_update_card(fitsFilePtr, kname, card, &status);
|
||||
}
|
||||
}
|
||||
|
||||
// hardcoded camera hardware version info keywords
|
||||
|
||||
fits_update_key_ulng(fitsFilePtr, "SERNUM", (ULONGLONG)_manager->_cameraSerialNumber, "Camera serial number",
|
||||
&status);
|
||||
|
||||
str = std::format("{}.{}", _manager->_microVersion[0], _manager->_microVersion[1]);
|
||||
fits_update_key_str(fitsFilePtr, "MICROVER", str.c_str(), "Camera microcontroller version", &status);
|
||||
|
||||
str = std::format("{}.{}", _manager->_FPGAVersion[0], _manager->_FPGAVersion[1]);
|
||||
fits_update_key_str(fitsFilePtr, "FPGAVER", str.c_str(), "Camera FPGA version", &status);
|
||||
|
||||
str = std::format("{}", _manager->_buildDate);
|
||||
fits_update_key_str(fitsFilePtr, "BUILDDAT", str.c_str(), "Camera build date, YY-MM-DD", &status);
|
||||
|
||||
fits_update_key_str(fitsFilePtr, "BUILDCOD", sv2cstr(_manager->_buildCode), "Camera build code", &status);
|
||||
|
||||
|
||||
fits_close_file(fitsFilePtr, &status);
|
||||
|
||||
fits_get_errstatus(status, err_str);
|
||||
|
||||
if (status) {
|
||||
_manager->logError("An error occured while writing FITS file '{}'! FITS status = {} ({})",
|
||||
_acqParams->filename, status, err_str);
|
||||
} else {
|
||||
_manager->logInfo("FITS file '{}' is saved", _acqParams->filename);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -782,8 +782,10 @@ void RaptorEagleCCD::startAquisition()
|
||||
.roiHeight = (*this)[CAMERA_ATTR_ROI_HEIGHT],
|
||||
.binX = (*this)[CAMERA_ATTR_XBIN],
|
||||
.binY = (*this)[CAMERA_ATTR_YBIN],
|
||||
.shutterState = (*this)[CAMERA_ATTR_SHUTTER_STATE],
|
||||
.readRate = (*this)[CAMERA_ATTR_READ_RATE],
|
||||
.readMode = (*this)[CAMERA_ATTR_READ_MODE],
|
||||
.gain = (*this)[CAMERA_ATTR_GAIN],
|
||||
.ccdTemp = (*this)[CAMERA_ATTR_CCD_TEMP],
|
||||
.tecSetPoint = (*this)[CAMERA_ATTR_TECPOINT],
|
||||
.tecState = (*this)[CAMERA_ATTR_TECSTATE] == CAMERA_ATTR_TECSTATE_ON ? true : false,
|
||||
@ -866,6 +868,8 @@ void RaptorEagleCCD::initAttrComm()
|
||||
{
|
||||
logDebug("Try to create attributes and commands ...");
|
||||
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
// helper to setup 8-bit register attributes
|
||||
// 'validator' is a callable with signature: std::pair<uchar, std::string> validator(const uchar&)
|
||||
auto create8BitAttr = [this](attr_ident_t name, auto reg_addr, auto&& validator, std::string_view log_mark) {
|
||||
@ -1373,9 +1377,7 @@ void RaptorEagleCCD::initAttrComm()
|
||||
}
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[](const attribute_t::serialized_t& v) {
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_TECSTATE_ON, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_TECSTATE_ON;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_TECSTATE_OFF, comp_case_ignore)) {
|
||||
@ -1469,9 +1471,7 @@ void RaptorEagleCCD::initAttrComm()
|
||||
logDebug("Readout mode is set to 0x{:02X} bits", bits);
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[](const attribute_t::serialized_t& v) {
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_READ_MODE_NORMAL, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_READ_MODE_NORMAL;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_READ_MODE_TEST, comp_case_ignore)) {
|
||||
@ -1522,9 +1522,7 @@ void RaptorEagleCCD::initAttrComm()
|
||||
logDebug("Readout rate is set to [0x{:02X}, 0x{:02X}] bytes", bytes[0], bytes[1]);
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[](const attribute_t::serialized_t& v) {
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_READ_RATE_FAST, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_READ_RATE_FAST;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_READ_RATE_SLOW, comp_case_ignore)) {
|
||||
@ -1578,9 +1576,7 @@ void RaptorEagleCCD::initAttrComm()
|
||||
logDebug("Shutter state is set to 0x{:02X}", bytes[0]);
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[](const attribute_t::serialized_t& v) {
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_SHUTTER_STATE_EXP, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_SHUTTER_STATE_EXP;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_SHUTTER_STATE_CLOSED, comp_case_ignore)) {
|
||||
@ -1714,9 +1710,7 @@ void RaptorEagleCCD::initAttrComm()
|
||||
logDebug("Trigger mode bits are set to 0b{:08b}", bits);
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[](const attribute_t::serialized_t& v) {
|
||||
auto comp_case_ignore = [](const auto& v1, const auto& v2) { return std::toupper(v1) == v2; };
|
||||
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_TRIGGER_MODE_EXT_RISING, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_TRIGGER_MODE_EXT_RISING;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_TRIGGER_MODE_EXT_FALLING, comp_case_ignore)) {
|
||||
@ -1732,5 +1726,38 @@ void RaptorEagleCCD::initAttrComm()
|
||||
return CAMERA_ATTR_STR_INVALID;
|
||||
});
|
||||
|
||||
|
||||
addAttribute(
|
||||
CAMERA_ATTR_GAIN,
|
||||
[this]() {
|
||||
auto bits = getFPGAState();
|
||||
|
||||
if (bits.test(CL_FPGA_CTRL_REG_HIGH_GAIN_BIT)) {
|
||||
return CAMERA_ATTR_GAIN_HIGH;
|
||||
} else {
|
||||
return CAMERA_ATTR_GAIN_LOW;
|
||||
}
|
||||
},
|
||||
[this](const std::string_view& gain) {
|
||||
if (gain == CAMERA_ATTR_GAIN_HIGH) {
|
||||
setFPGAStateBit(CL_FPGA_CTRL_REG_HIGH_GAIN_BIT);
|
||||
} else if (gain == CAMERA_ATTR_GAIN_LOW) {
|
||||
clearFPGAStateBit(CL_FPGA_CTRL_REG_HIGH_GAIN_BIT);
|
||||
} else {
|
||||
logWarn("Invalid gain mode! Set it to {}", CL_FPGA_CTRL_REG_HIGH_GAIN_BIT);
|
||||
setFPGAStateBit(CL_FPGA_CTRL_REG_HIGH_GAIN_BIT);
|
||||
}
|
||||
},
|
||||
adc::utils::AdcDefaultValueConverter<>::serialize<attribute_t::serialized_t, std::string_view>,
|
||||
[&comp_case_ignore](const attribute_t::serialized_t& v) {
|
||||
if (std::ranges::equal(v, CAMERA_ATTR_GAIN_HIGH, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_GAIN_HIGH;
|
||||
} else if (std::ranges::equal(v, CAMERA_ATTR_GAIN_LOW, comp_case_ignore)) {
|
||||
return CAMERA_ATTR_GAIN_LOW;
|
||||
}
|
||||
|
||||
return CAMERA_ATTR_STR_INVALID;
|
||||
});
|
||||
|
||||
logDebug("Attributes and commands are successfully created!");
|
||||
}
|
||||
|
||||
@ -126,6 +126,9 @@ public:
|
||||
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
|
||||
@ -162,8 +165,10 @@ private:
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user