introduced new type Hz, typetraits, String conversions, command generation (not yet generated)

This commit is contained in:
2026-03-27 16:52:58 +01:00
parent 2372f93dd9
commit fa9c2de307
14 changed files with 230 additions and 55 deletions
@@ -66,7 +66,8 @@ uint8_t adcEnableMask_10g = 0xFF;
uint32_t transceiverMask = DEFAULT_TRANSCEIVER_MASK;
int32_t clkPhase[NUM_CLOCKS] = {};
uint32_t clkFrequency[NUM_CLOCKS] = {DEFAULT_RUN_CLK, DEFAULT_ADC_CLK, DEFAULT_SYNC_CLK, DEFAULT_DBIT_CLK};
uint32_t clkFrequency[NUM_CLOCKS] = {DEFAULT_RUN_CLK, DEFAULT_ADC_CLK,
DEFAULT_SYNC_CLK, DEFAULT_DBIT_CLK};
int dacValues[NDAC] = {};
// software limit that depends on the current chip on the ctb
int vLimit = 0;
@@ -2125,9 +2126,8 @@ int getMaxPhase(enum CLKINDEX ind) {
MAX_PHASE_SHIFTS_STEPS;
char *clock_names[] = {CLK_NAMES};
LOG(logDEBUG1,
("Max Phase Shift (%s): %d (Clock: %d MHz, VCO:%d Hz)\n",
clock_names[ind], ret, clkFrequency[ind], PLL_VCO_FREQ_HZ));
LOG(logDEBUG1, ("Max Phase Shift (%s): %d (Clock: %d MHz, VCO:%d Hz)\n",
clock_names[ind], ret, clkFrequency[ind], PLL_VCO_FREQ_HZ));
return ret;
}
@@ -2209,16 +2209,17 @@ int getFrequency(enum CLKINDEX ind) {
LOG(logERROR, ("Unknown clock index %d to get frequency\n", ind));
return -1;
}
#ifndef VIRTUAL
// get the measured frequency from the firmware
int measuredFreqHz = ALTERA_PLL_getFrequency(ind);
#ifndef VIRTUAL
// get the measured frequency from the firmware
int measuredFreqHz = ALTERA_PLL_getFrequency(ind);
// checking against 0 here ensures compatibility with old firmware, TODO: remove this check at some point
if (measuredFreqHz != 0) {
// Round to nearest MHz. (should we round at all ?)
clkFrequency[ind] = measuredFreqHz;
}
#endif VIRTUAL
// checking against 0 here ensures compatibility with old firmware, TODO:
// remove this check at some point
if (measuredFreqHz != 0) {
// Round to nearest MHz. (should we round at all ?)
clkFrequency[ind] = measuredFreqHz;
}
#endif
return clkFrequency[ind];
}
@@ -51,8 +51,8 @@
#define DEFAULT_TIMING_MODE (AUTO_TIMING)
#define DEFAULT_TX_UDP_PORT (0x7e9a)
#define DEFAULT_RUN_CLK (80000000) // 80
#define DEFAULT_ADC_CLK (40000000) // 40
#define DEFAULT_SYNC_CLK (40000000) // 40
#define DEFAULT_ADC_CLK (40000000) // 40
#define DEFAULT_SYNC_CLK (40000000) // 40
#define DEFAULT_DBIT_CLK (200000000)
#define NS_TO_CLK_CYCLE (1E-9) // ns to MHz
#define DEFAULT_TRANSCEIVER_MASK (0x3)
@@ -95,7 +95,7 @@
#define BIT32_MSK (0xFFFFFFFF)
#define BIT16_MASK (0xFFFF)
#define MAXIMUM_ADC_CLK (65000000)
#define MAXIMUM_ADC_CLK (65000000)
#define PLL_VCO_FREQ_HZ (800000000)
/* Struct Definitions */
@@ -328,12 +328,12 @@ int ALTERA_PLL_SetOutputFrequency(int clkIndex, int pllVCOFreqHz, int value) {
return (int)temp;
*/
#if defined(CHIPTESTBOARDD) && !defined(VIRTUAL)
// wait for firmware to measure the actual frequency
usleep(2 * 1000 * 1000);
value = ALTERA_PLL_getFrequency(clkIndex);
LOG(logDEBUG1, ("Frequency is %d\n", value));
#endif
#if defined(CHIPTESTBOARDD) && !defined(VIRTUAL)
// wait for firmware to measure the actual frequency
usleep(2 * 1000 * 1000);
value = ALTERA_PLL_getFrequency(clkIndex);
LOG(logDEBUG1, ("Frequency is %d\n", value));
#endif
return value;
}
@@ -5869,7 +5869,8 @@ int set_clock_frequency(int file_des) {
} else {
int ret = setFrequency(c, val);
if (ret == FAIL) {
sprintf(mess, "Could not set %s to %d %s\n", modeName, val,"Hz");
sprintf(mess, "Could not set %s to %d %s\n", modeName, val,
"Hz");
LOG(logERROR, (mess));
} else {
int retval = getFrequency(c);
@@ -5930,8 +5931,8 @@ int get_clock_frequency(int file_des) {
if (ret == OK) {
retval = getFrequency(c);
char *clock_names[] = {CLK_NAMES};
LOG(logDEBUG1,
("retval %s clock (%d) frequency: %d %s\n", clock_names[c], (int)c, retval, "Hz"));
LOG(logDEBUG1, ("retval %s clock (%d) frequency: %d %s\n",
clock_names[c], (int)c, retval, "Hz"));
}
#endif
return Server_SendResult(file_des, INT32, &retval, sizeof(retval));
@@ -16,6 +16,7 @@ type_values = {
'special::mv': ["mv", "mV"],
"special::deg": ["deg"],
"special::time_unit": ["s", "ms", "us", "ns"],
"special::freq_unit": ["Hz", "KHz", "MHz"],
"special::hard": ["hard"],
"special::force-delete-normal-file": ["--force-delete-normal-file"],
"special::currentSourceFix": ["fix", "nofix"],
+64 -26
View File
@@ -2,6 +2,41 @@
# detectors: MYTHEN3
################# TEMPLATES #################
FREQ_COMMAND:
infer_action: true
help: ""
template: true
actions:
GET:
require_det_id: true
function: ''
args:
- argc: 0
output: [ OutString(t) ]
- argc: 1
arg_types: [ special::freq_unit ]
output: [ "OutString(t , args[0])" ]
PUT:
function: ''
require_det_id: true
input: [ converted_freq ]
input_types: [ defs::Hz ]
args:
- argc: 1
arg_types: [ std::string ]
separate_freq_units:
input: 'args[0]'
output: [ converted_freq, unit ]
output: [ 'args[0]' ]
- argc: 2
arg_types: [ int, special::freq_unit ]
convert_to_freq:
input: [ 'args[0]', 'args[1]' ]
output: converted_freq
output: [ 'args[0]', 'args[1]' ]
TIME_COMMAND:
infer_action: true
help: ""
@@ -429,6 +464,35 @@ CTB_GET_INDEX:
################# COMMANDS ##################################
################# FREQ_COMMAND #############
adcclk:
help: "[n_clk] [(optional unit) Hz(default)|KHz|MHz]\n\t[Ctb][Xilinx Ctb] ADC clock frequency."
inherit_actions: FREQ_COMMAND
actions:
GET:
function: getADCClock
PUT:
function: setADCClock
runclk:
help: "[n_clk] [(optional unit) Hz(default)|KHz|MHz]\n\t[Ctb][Xilinx Ctb] Run clock frequency."
inherit_actions: FREQ_COMMAND
actions:
GET:
function: getRunClock
PUT:
function: setRunClock
dbitclk:
help: "[n_clk] [(optional unit) Hz(default)|KHz|MHz]\n\t[Ctb][Xilinx Ctb] Clock for latching the digital bits."
inherit_actions: FREQ_COMMAND
actions:
GET:
function: getDBitClock
PUT:
function: setDBitClock
################# TIME_COMMAND #############
period:
@@ -1271,23 +1335,6 @@ asamples:
PUT:
function: setNumberOfAnalogSamples
adcclk:
help: "[n_clk in MHz]\n\t[Ctb][xilinx Ctb] ADC clock frequency in MHz."
inherit_actions: INTEGER_COMMAND_VEC_ID
actions:
GET:
function: getADCClock
PUT:
function: setADCClock
runclk:
help: "[n_clk in MHz]\n\t[Ctb][xilinx Ctb] Run clock in MHz."
inherit_actions: INTEGER_COMMAND_VEC_ID
actions:
GET:
function: getRUNClock
PUT:
function: setRUNClock
dsamples:
help: "[n_value]\n\t[Ctb] Number of digital samples expected."
@@ -1317,15 +1364,6 @@ romode:
function: setReadoutMode
input_types: [ defs::readoutMode ]
dbitclk:
help: "[n_clk in MHz]\n\t[Ctb][xilinx Ctb] Clock for latching the digital bits in MHz."
inherit_actions: INTEGER_COMMAND_VEC_ID
actions:
GET:
function: getDBITClock
PUT:
function: setDBITClock
extsampling:
help: "[0, 1]\n\t[Ctb] Enable for external sampling signal for digital data to signal by extsampling src command. For advanced users only."
inherit_actions: INTEGER_COMMAND_VEC_ID
@@ -50,7 +50,6 @@ class CommandParser:
if len(arg['input_types']) != len(arg['input']):
raise ValueError(f'Argument {arg} does not have the correct number of inputs')
if 'separate_time_units' in arg:
if arg['separate_time_units']['input'] == "":
raise ValueError(f'Argument {arg} does not have the correct number of inputs for separate_time_units')
if len(arg['separate_time_units']['output']) != 2:
@@ -60,6 +59,16 @@ class CommandParser:
raise ValueError(f'Argument {arg} does not have the correct number of inputs for convert_to_time')
if len(arg['convert_to_time']['output']) == "":
raise ValueError(f'Argument {arg} does not have the correct number of outputs for convert_to_time')
if 'separate_freq_units' in arg:
if arg['separate_freq_units']['input'] == "":
raise ValueError(f'Argument {arg} does not have the correct number of inputs for separate_freq_units')
if len(arg['separate_freq_units']['output']) != 2:
raise ValueError(f'Argument {arg} does not have the correct number of outputs for separate_freq_units')
if 'convert_to_freq' in arg:
if len(arg['convert_to_freq']['input']) != 2:
raise ValueError(f'Argument {arg} does not have the correct number of inputs for convert_to_freq')
if len(arg['convert_to_freq']['output']) == "":
raise ValueError(f'Argument {arg} does not have the correct number of outputs for convert_to_freq')
# if infer_action:
# if arg['argc'] in self.argc_set:
# raise ValueError(f'Argument {arg} has a duplicate argc')
@@ -137,6 +137,16 @@ class CodeGenerator:
if 'convert_to_time' in arg and arg['convert_to_time']:
self.write_line(f'auto {arg["convert_to_time"]["output"]} = '
f'StringTo < time::ns > ({", ".join(arg["convert_to_time"]["input"])});')
if 'separate_freq_units' in arg and arg['separate_freq_units']:
self.write_line(f'std::string tmp_freq({arg["separate_freq_units"]["input"]});')
self.write_line(f'std::string {arg["separate_freq_units"]["output"][1]}'
f' = RemoveUnit(tmp_freq);')
self.write_line(f'auto {arg["separate_freq_units"]["output"][0]} = '
f'StringTo < defs::Hz > (tmp_freq,'
f' {arg["separate_freq_units"]["output"][1]});')
if 'convert_to_freq' in arg and arg['convert_to_freq']:
self.write_line(f'auto {arg["convert_to_freq"]["output"]} = '
f'StringTo < defs::Hz > ({", ".join(arg["convert_to_freq"]["input"])});')
input_arguments = []
if 'exceptions' in arg:
for exception in arg['exceptions']:
@@ -119,7 +119,25 @@ def generate(
f'StringTo < time::ns > ({", ".join(arg["convert_to_time"]["input"])});')
codegen.write_line(
f'}} catch (...) {{ throw RuntimeError("Could not convert arguments to time::ns");}}')
elif 'separate_freq_units' in arg and arg['separate_freq_units']:
codegen.write_line(f'try {{')
# TODO: refactor this repeating code
codegen.write_line(f'std::string tmp_freq({arg["separate_freq_units"]["input"]});')
codegen.write_line(f'std::string {arg["separate_freq_units"]["output"][1]}'
f' = RemoveUnit(tmp_freq);')
codegen.write_line(f'auto {arg["separate_freq_units"]["output"][0]} = '
f'StringTo < defs::Hz > (tmp_freq,'
f' {arg["separate_freq_units"]["output"][1]});')
codegen.write_line(
f'}} catch (...) {{ throw RuntimeError("Could not convert argument to defs::Hz");}}')
elif 'convert_to_freq' in arg and arg['convert_to_freq']:
codegen.write_line(f'try {{')
codegen.write_line(
f'StringTo < defs::Hz > ({", ".join(arg["convert_to_freq"]["input"])});')
codegen.write_line(
f'}} catch (...) {{ throw RuntimeError("Could not convert arguments to defs::Hz");}}')
for i in range(len(arg['input'])):
if not arg['cast_input'][i]:
continue
+7 -1
View File
@@ -302,7 +302,13 @@ write_arg in codegen reads the argument fields and generate c++ code accordingly
std::string $output[1]$ = RemoveUnit(tmp_time);
auto $output[0]$ = StringTo<time::ns>(tmp_time, $output[1]$);
```
- convert_to_time: takes three parameters: input[0], input[1], output
- separate_freq_units: takes three parameters: input, output[0], output[1] each one is a variable name
```cpp
std::string tmp_freq($input$);
std::string $output[1]$ = RemoveUnit(tmp_freq);
auto $output[0]$ = StringTo<defs::Hz>(tmp_freq, $output[1]$);
```
- convert_to_time and convert_to_freq: takes three parameters: input[0], input[1], output
```cpp
auto output = StringTo<time::ns>(input[0], input[1]);
```
+60 -1
View File
@@ -105,6 +105,38 @@ ToString(From t) {
}
}
/** Convert frequency with specified output unit */
template <typename T, typename Rep = double>
typename std::enable_if<is_frequency<T>::value, std::string>::type
ToString(T f, const std::string &unit) {
double val = static_cast<double>(f.value);
std::ostringstream os;
if (unit == "Hz")
os << val << ' ' << unit;
else if (unit == "kHz")
os << val / (static_cast<double>(1e3)) << ' ' << unit;
else if (unit == "MHz")
os << val / (static_cast<double>(1e6)) << ' ' << unit;
else
throw std::runtime_error("Unknown unit: " + unit);
return os.str();
}
/** Convert frequency automatically selecting the unit */
template <typename From>
typename std::enable_if<is_frequency<From>::value, std::string>::type
ToString(From f) {
int val = f.value;
if (val < 1e3) {
return ToString(f, "Hz");
} else if (val < 1e6) {
return ToString(f, "kHz");
} else {
return ToString(f, "MHz");
}
}
/** Conversion of floating point values, removes trailing zeros*/
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, std::string>::type
@@ -276,7 +308,7 @@ ToString(const T &container, const std::string &unit) {
return os.str();
}
template <typename T>
template <typename T, std::enable_if_t<sls::is_duration<T>::value, int> = 0>
T StringTo(const std::string &t, const std::string &unit) {
double tval{0};
try {
@@ -301,6 +333,33 @@ T StringTo(const std::string &t, const std::string &unit) {
}
}
template <typename T, std::enable_if_t<sls::is_frequency<T>::value, int> = 0>
T StringTo(const std::string &f, const std::string &unit) {
double fval{0};
try {
fval = std::stod(f);
} catch (const std::invalid_argument &e) {
throw RuntimeError("Could not convert string to frequency");
}
auto unitLower = [&] {
std::string result = unit;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}();
if (unitLower.empty() || unitLower == "mhz") {
return T(static_cast<int>(fval * 1e6));
} else if (unitLower == "khz") {
return T(static_cast<int>(fval * 1e3));
} else if (unitLower == "hz") {
return T(static_cast<int>(fval));
} else {
throw RuntimeError(
"Invalid unit in conversion from string to frequency");
}
}
template <typename T> T StringTo(const std::string &t) {
std::string tmp{t};
auto unit = RemoveUnit(tmp);
+7
View File
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include "sls/sls_detector_defs.h"
#include <type_traits>
#include <vector>
@@ -120,4 +122,9 @@ struct has_bool_isValid : std::false_type {};
template <typename T>
struct has_bool_isValid<T, std::void_t<decltype(std::declval<T>().isValid)>>
: std::is_same<decltype(std::declval<T>().isValid), bool> {};
template <typename T> struct is_frequency : std::false_type {};
template <> struct is_frequency<defs::Hz> : std::true_type {};
} // namespace sls
@@ -209,6 +209,14 @@ class slsDetectorDefs {
std::map<std::string, std::string> addJsonHeader;
};
struct Hz {
int value{0};
explicit Hz(int v) : value(v){};
constexpr bool operator==(const Hz &other) const {
return (value == other.value);
}
};
#endif
enum frameDiscardPolicy {
NO_DISCARD,
@@ -833,7 +841,6 @@ typedef struct {
#endif
#ifdef __cplusplus
// TODO! discuss this
#include <vector> //hmm... but currently no way around
namespace sls {
+18
View File
@@ -58,6 +58,15 @@ TEST_CASE("conversion from duration to string", "[support]") {
REQUIRE(ToString(us(-100)) == "-100us");
}
TEST_CASE("conversion from frequency to string", "[support]") {
REQUIRE(ToString(defs::Hz(150)) == "150 Hz");
REQUIRE(ToString(defs::Hz(1500)) == "1.5 kHz");
REQUIRE(ToString(defs::Hz(1500000)) == "1.5 MHz");
REQUIRE(ToString(defs::Hz(150), "Hz") == "150 Hz");
REQUIRE(ToString(defs::Hz(150), "kHz") == "0.15 kHz");
REQUIRE(ToString(defs::Hz(150), "MHz") == "0.00015 MHz");
}
TEST_CASE("Convert vector of time", "[support]") {
std::vector<ns> vec{ns(150), us(10), ns(600)};
REQUIRE(ToString(vec) == "[150ns, 10us, 600ns]");
@@ -137,6 +146,15 @@ TEST_CASE("string to std::chrono::duration", "[support]") {
REQUIRE_THROWS(StringTo<ns>("asvn"));
}
TEST_CASE("string to frequency", "[support]") {
REQUIRE(StringTo<defs::Hz>("150", "Hz") == defs::Hz(150));
REQUIRE(StringTo<defs::Hz>("150Hz") == defs::Hz(150));
REQUIRE(StringTo<defs::Hz>("1.5 kHz") == defs::Hz(1500));
REQUIRE(StringTo<defs::Hz>("1.5MHz") == defs::Hz(1500000));
REQUIRE_THROWS(StringTo<defs::Hz>("5xs"));
REQUIRE_THROWS(StringTo<defs::Hz>("asvn"));
}
TEST_CASE("string to detectorType") {
using dt = slsDetectorDefs::detectorType;
REQUIRE(StringTo<dt>("Eiger") == dt::EIGER);