diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index 46b1fde51..5498d432c 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -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]; } diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h index 8ebe24b42..2e95c08a1 100644 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h @@ -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 */ diff --git a/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c b/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c index ba5cce501..eed289ae5 100644 --- a/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c +++ b/slsDetectorServers/slsDetectorServer/src/ALTERA_PLL.c @@ -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; } diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index bb00c00fa..39c776571 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -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)); diff --git a/slsDetectorSoftware/generator/autocomplete/autocomplete.py b/slsDetectorSoftware/generator/autocomplete/autocomplete.py index 356e82eab..c4b11838c 100644 --- a/slsDetectorSoftware/generator/autocomplete/autocomplete.py +++ b/slsDetectorSoftware/generator/autocomplete/autocomplete.py @@ -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"], diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 5c6bed695..5c0365554 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -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 diff --git a/slsDetectorSoftware/generator/commands_parser/commands_parser.py b/slsDetectorSoftware/generator/commands_parser/commands_parser.py index 9a11cd789..576cbfa21 100644 --- a/slsDetectorSoftware/generator/commands_parser/commands_parser.py +++ b/slsDetectorSoftware/generator/commands_parser/commands_parser.py @@ -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') diff --git a/slsDetectorSoftware/generator/cpp_codegen/codegen.py b/slsDetectorSoftware/generator/cpp_codegen/codegen.py index dc5e3294f..0c0724cbe 100644 --- a/slsDetectorSoftware/generator/cpp_codegen/codegen.py +++ b/slsDetectorSoftware/generator/cpp_codegen/codegen.py @@ -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']: diff --git a/slsDetectorSoftware/generator/gen_commands.py b/slsDetectorSoftware/generator/gen_commands.py index ee4f97a8c..07f563a34 100644 --- a/slsDetectorSoftware/generator/gen_commands.py +++ b/slsDetectorSoftware/generator/gen_commands.py @@ -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 diff --git a/slsDetectorSoftware/generator/readme.md b/slsDetectorSoftware/generator/readme.md index e86c4fad5..ab4ed3a9d 100644 --- a/slsDetectorSoftware/generator/readme.md +++ b/slsDetectorSoftware/generator/readme.md @@ -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(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(tmp_freq, $output[1]$); + ``` +- convert_to_time and convert_to_freq: takes three parameters: input[0], input[1], output ```cpp auto output = StringTo(input[0], input[1]); ``` diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index c9eb15f2b..14fda7539 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -105,6 +105,38 @@ ToString(From t) { } } +/** Convert frequency with specified output unit */ +template +typename std::enable_if::value, std::string>::type +ToString(T f, const std::string &unit) { + double val = static_cast(f.value); + + std::ostringstream os; + if (unit == "Hz") + os << val << ' ' << unit; + else if (unit == "kHz") + os << val / (static_cast(1e3)) << ' ' << unit; + else if (unit == "MHz") + os << val / (static_cast(1e6)) << ' ' << unit; + else + throw std::runtime_error("Unknown unit: " + unit); + return os.str(); +} + +/** Convert frequency automatically selecting the unit */ +template +typename std::enable_if::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 std::enable_if::value, std::string>::type @@ -276,7 +308,7 @@ ToString(const T &container, const std::string &unit) { return os.str(); } -template +template ::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 ::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(fval * 1e6)); + } else if (unitLower == "khz") { + return T(static_cast(fval * 1e3)); + } else if (unitLower == "hz") { + return T(static_cast(fval)); + } else { + throw RuntimeError( + "Invalid unit in conversion from string to frequency"); + } +} + template T StringTo(const std::string &t) { std::string tmp{t}; auto unit = RemoveUnit(tmp); diff --git a/slsSupportLib/include/sls/TypeTraits.h b/slsSupportLib/include/sls/TypeTraits.h index 1a153e67b..926b2227d 100644 --- a/slsSupportLib/include/sls/TypeTraits.h +++ b/slsSupportLib/include/sls/TypeTraits.h @@ -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 #include @@ -120,4 +122,9 @@ struct has_bool_isValid : std::false_type {}; template struct has_bool_isValid().isValid)>> : std::is_same().isValid), bool> {}; + +template struct is_frequency : std::false_type {}; + +template <> struct is_frequency : std::true_type {}; + } // namespace sls \ No newline at end of file diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index a5ccb2566..f4b4c5c7a 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -209,6 +209,14 @@ class slsDetectorDefs { std::map 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 //hmm... but currently no way around namespace sls { diff --git a/slsSupportLib/tests/test-ToString.cpp b/slsSupportLib/tests/test-ToString.cpp index 76ee87245..e577423e4 100644 --- a/slsSupportLib/tests/test-ToString.cpp +++ b/slsSupportLib/tests/test-ToString.cpp @@ -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 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("asvn")); } +TEST_CASE("string to frequency", "[support]") { + REQUIRE(StringTo("150", "Hz") == defs::Hz(150)); + REQUIRE(StringTo("150Hz") == defs::Hz(150)); + REQUIRE(StringTo("1.5 kHz") == defs::Hz(1500)); + REQUIRE(StringTo("1.5MHz") == defs::Hz(1500000)); + REQUIRE_THROWS(StringTo("5xs")); + REQUIRE_THROWS(StringTo("asvn")); +} + TEST_CASE("string to detectorType") { using dt = slsDetectorDefs::detectorType; REQUIRE(StringTo
("Eiger") == dt::EIGER);