aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt1
-rw-r--r--host/include/uhd/rfnoc/defaults.hpp1
-rw-r--r--host/include/uhd/rfnoc/siggen_block_control.hpp207
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/siggen_block_control.cpp343
5 files changed, 553 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
index 7a1602f90..965710a59 100644
--- a/host/include/uhd/rfnoc/CMakeLists.txt
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -44,6 +44,7 @@ UHD_INSTALL(FILES
moving_average_block_control.hpp
null_block_control.hpp
radio_control.hpp
+ siggen_block_control.hpp
split_stream_block_control.hpp
switchboard_block_control.hpp
vector_iir_block_control.hpp
diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp
index ac230b57d..781beb696 100644
--- a/host/include/uhd/rfnoc/defaults.hpp
+++ b/host/include/uhd/rfnoc/defaults.hpp
@@ -82,6 +82,7 @@ static const noc_id_t FIR_FILTER_BLOCK = 0xF1120000;
static const noc_id_t FOSPHOR_BLOCK = 0x666F0000;
static const noc_id_t LOGPWR_BLOCK = 0x4C500000;
static const noc_id_t MOVING_AVERAGE_BLOCK = 0xAAD20000;
+static const noc_id_t SIGGEN_BLOCK = 0x51663110;
static const noc_id_t SPLIT_STREAM_BLOCK = 0x57570000;
static const noc_id_t SWITCHBOARD_BLOCK = 0xBE110000;
static const noc_id_t RADIO_BLOCK = 0x12AD1000;
diff --git a/host/include/uhd/rfnoc/siggen_block_control.hpp b/host/include/uhd/rfnoc/siggen_block_control.hpp
new file mode 100644
index 000000000..944ecc4e0
--- /dev/null
+++ b/host/include/uhd/rfnoc/siggen_block_control.hpp
@@ -0,0 +1,207 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#define _USE_MATH_DEFINES
+#include <uhd/config.hpp>
+#include <uhd/rfnoc/noc_block_base.hpp>
+#include <cmath>
+#include <complex>
+
+namespace uhd { namespace rfnoc {
+
+/*! Siggen Control Class
+ *
+ * The Siggen Block is an RFNoC block that acts as a simple function
+ * generating source block. The block supports three functions: generating a
+ * constant value, generating a sinusoidal wave with a configurable amplitude
+ * and phase increment between samples (but with a random initial phase
+ * offset), and a noise source.
+ */
+
+enum class siggen_waveform { CONSTANT, SINE_WAVE, NOISE };
+
+class UHD_API siggen_block_control : public noc_block_base
+{
+public:
+ RFNOC_DECLARE_BLOCK(siggen_block_control);
+
+ static const uint32_t REG_BLOCK_SIZE;
+ static const uint32_t REG_ENABLE_OFFSET;
+ static const uint32_t REG_SPP_OFFSET;
+ static const uint32_t REG_WAVEFORM_OFFSET;
+ static const uint32_t REG_GAIN_OFFSET;
+ static const uint32_t REG_CONSTANT_OFFSET;
+ static const uint32_t REG_PHASE_INC_OFFSET;
+ static const uint32_t REG_CARTESIAN_OFFSET;
+
+ /*! Set the function generator stream enable flag
+ *
+ * Enables or disables the stream of function generator data from the
+ * given port on the block.
+ *
+ * \param enable Stream enable/disable flag
+ * \param port The port on the block to enable or disable
+ */
+ virtual void set_enable(const bool enable, const size_t port) = 0;
+
+ /*! Get the function generator stream enable flag
+ *
+ * Returns the current enable flag for function generator stream data from
+ * the given port on the block.
+ *
+ * \param port The port on the block to get the flag from
+ * \returns Function generator stream data enable/disable flag
+ */
+ virtual bool get_enable(const size_t port) const = 0;
+
+ /*! Set the function generator waveform type
+ *
+ * Sets the waveform type that the given port on the block should generate
+ * when enabled.
+ *
+ * \param type Function generator waveform type
+ * \param port The port on the block whose waveform type to set
+ */
+ virtual void set_waveform(const siggen_waveform type, const size_t port) = 0;
+
+ /*! Get the function generator waveform type
+ *
+ * Returns the current waveform type for the given port on the block.
+ *
+ * \param port The port on the block whose waveform type to return
+ * \returns Waveform type
+ */
+ virtual siggen_waveform get_waveform(const size_t port) const = 0;
+
+ /*! Set the amplitude value for noise and sine wave data
+ *
+ * Sets the maximum amplitude of the data generated by the given port
+ * on the block. The hardware can generate function data with an
+ * amplitude between -1.0 and (2^15-1)/(2^15), or approximately 0.99997,
+ * so the provided value must reside within this range. However, for
+ * convenience, clients may pass 1.0 to get the maximum amplitude that
+ * can be generated.
+ *
+ * Setting the amplitude applies only to the noise and to the sine wave
+ * functions. The value generated when in constant mode is the value that
+ * is configured via the set_constant() function. Calling this function
+ * when in constant mode will range check the amplitude value, but will
+ * otherwise have no impact on the generated signal.
+ *
+ * \param amplitude Amplitude of sine wave and noise data
+ * \param port The port on the block whose amplitude value to set
+ */
+ virtual void set_amplitude(const double amplitude, const size_t port) = 0;
+
+ /*! Get the amplitude value for noise and sine wave data
+ *
+ * Returns the current maximum amplitude of the data generated by
+ * the given port on the block. The value only applies to the noise and
+ * sine wave functions. Calling this function when in constant mode will
+ * return 1.0.
+ *
+ * \param port The port on the block whose amplitude value to return
+ * \returns Amplitude value
+ */
+ virtual double get_amplitude(const size_t port) const = 0;
+
+ /*! Set the constant value to generate in constant mode
+ *
+ * Sets the value that should be generated by the function generator on
+ * the given block when the block is configured in constant mode. The
+ * hardware can output a complex value where the real and imaginary
+ * components can be between -1.0 and (2^15-1)/(2^15), or approximately
+ * 0.99997, so the provided value must reside within this range. However,
+ * for convenience, clients may pass 1.0 for either component to get the
+ * maximum positive value that can be generated.
+ *
+ * \param constant The constant value to generate
+ * \param port The port on the block whose constant value to set
+ */
+ virtual void set_constant(const std::complex<double> constant, const size_t port) = 0;
+
+ /*! Get the constant value to generate in constant mode
+ *
+ * Returns the current constant value to be generated by the function
+ * generator on the given block when the block is configured in constant
+ * mode.
+ *
+ * \param port The port on the block whose constant value to return
+ * \returns Constant value to generate
+ */
+ virtual std::complex<double> get_constant(const size_t port) const = 0;
+
+ /*! Set the phase increment between samples in sine wave mode
+ *
+ * Sets the phase increment between successive samples generated by the
+ * function generator on the given block when the block is configured in
+ * sine wave mode. The value must be in the range [-pi, pi].
+ *
+ * \param phase_inc The phase increment between samples
+ * \param port The port on the block whose phase increment to set
+ */
+ virtual void set_sine_phase_increment(const double phase_inc, const size_t port) = 0;
+
+ /*! Get the phase increment between samples in sine wave mode
+ *
+ * Returns the current phase increment between successive samples generated
+ * by the function generator on the given block when the block is
+ * configured in sine wave mode.
+ *
+ * \param port The port on the block whose phase increment to return
+ * \returns Phase increment between samples
+ */
+ virtual double get_sine_phase_increment(const size_t port) const = 0;
+
+ /*! Set the number of samples per packet to generate
+ *
+ * Sets the number of samples per packet to be generated by the function
+ * generator on the given block. The value will be coerced such that
+ * outgoing packets will not exceed the graph MTU.
+ *
+ * \param spp Number of samples per packet to generate
+ * \param port The port on the block whose samples per packet to set
+ */
+ virtual void set_samples_per_packet(const size_t spp, const size_t port) = 0;
+
+ /*! Get the number of samples per packet to generate
+ *
+ * Returns the current number of samples per packet generated by the
+ * function generator on the given block.
+ *
+ * \param port The port on the block whose samples per packet value to get
+ * \returns Number of samples per packet to generate
+ */
+ virtual size_t get_samples_per_packet(const size_t port) const = 0;
+
+ /*! Configure the sinusoidal waveform generator given frequency and rate
+ *
+ * Convenience function to configure the current phase increment between
+ * successive samples generated by the sinusoidal function generator
+ * given the desired frequency and assumed sample rate.
+ *
+ * \param frequency The desired frequency of the sinusoid
+ * \param sample_rate The assumed sample rate
+ * \param port The port on the block whose phase increment to set
+ */
+ inline void set_sine_frequency(
+ const double frequency, const double sample_rate, const size_t port)
+ {
+ if (sample_rate <= 0.0) {
+ throw uhd::value_error("sample_rate must be > 0.0");
+ }
+ const double phase_inc = (frequency / sample_rate) * 2.0 * M_PI;
+ if (phase_inc < -M_PI || phase_inc > M_PI) {
+ throw uhd::value_error("frequency must be in [-samp_rate/2, samp_rate/2]");
+ }
+ set_sine_phase_increment(phase_inc, port);
+ }
+};
+
+}} // namespace uhd::rfnoc
+
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index a9c3c9ed0..233c536bf 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -52,6 +52,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/moving_average_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/null_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/siggen_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/split_stream_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/switchboard_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vector_iir_block_control.cpp
diff --git a/host/lib/rfnoc/siggen_block_control.cpp b/host/lib/rfnoc/siggen_block_control.cpp
new file mode 100644
index 000000000..416688ce1
--- /dev/null
+++ b/host/lib/rfnoc/siggen_block_control.cpp
@@ -0,0 +1,343 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#define _USE_MATH_DEFINES
+#include <uhd/convert.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
+#include <uhd/rfnoc/property.hpp>
+#include <uhd/rfnoc/registry.hpp>
+#include <uhd/rfnoc/siggen_block_control.hpp>
+#include <uhdlib/utils/narrow.hpp>
+#include <cmath>
+#include <limits>
+#include <string>
+
+using namespace uhd::rfnoc;
+
+
+// Register offsets
+const uint32_t siggen_block_control::REG_BLOCK_SIZE = 1 << 5;
+const uint32_t siggen_block_control::REG_ENABLE_OFFSET = 0x00;
+const uint32_t siggen_block_control::REG_SPP_OFFSET = 0x04;
+const uint32_t siggen_block_control::REG_WAVEFORM_OFFSET = 0x08;
+const uint32_t siggen_block_control::REG_GAIN_OFFSET = 0x0C;
+const uint32_t siggen_block_control::REG_CONSTANT_OFFSET = 0x10;
+const uint32_t siggen_block_control::REG_PHASE_INC_OFFSET = 0x14;
+const uint32_t siggen_block_control::REG_CARTESIAN_OFFSET = 0x18;
+
+// User property names
+const char* const PROP_KEY_ENABLE = "enable";
+const char* const PROP_KEY_WAVEFORM = "waveform";
+const char* const PROP_KEY_AMPLITUDE = "amplitude";
+const char* const PROP_KEY_CONSTANT_I = "constant_i";
+const char* const PROP_KEY_CONSTANT_Q = "constant_q";
+const char* const PROP_KEY_SINE_PHASE_INC = "sine_phase_increment";
+
+namespace {
+template <class T>
+const T clamp(const double v)
+{
+ constexpr T min_t = std::numeric_limits<T>::min();
+ constexpr T max_t = std::numeric_limits<T>::max();
+ return (v < min_t) ? min_t : (v > max_t) ? max_t : T(v);
+}
+} // namespace
+
+class siggen_block_control_impl : public siggen_block_control
+{
+public:
+ RFNOC_BLOCK_CONSTRUCTOR(siggen_block_control),
+ _siggen_reg_iface(*this, 0, REG_BLOCK_SIZE)
+ {
+ _register_props();
+ }
+
+ void set_enable(const bool enable, const size_t port)
+ {
+ set_property<bool>(PROP_KEY_ENABLE, enable, port);
+ }
+
+ bool get_enable(const size_t port) const
+ {
+ return _prop_enable.at(port).get();
+ }
+
+ void set_waveform(const siggen_waveform waveform, const size_t port)
+ {
+ set_property<int>(PROP_KEY_WAVEFORM, static_cast<int>(waveform), port);
+ }
+
+ siggen_waveform get_waveform(const size_t port) const
+ {
+ return static_cast<siggen_waveform>(_prop_waveform.at(port).get());
+ }
+
+ void set_amplitude(const double amplitude, const size_t port)
+ {
+ set_property<double>(PROP_KEY_AMPLITUDE, amplitude, port);
+ }
+
+ double get_amplitude(const size_t port) const
+ {
+ return _prop_amplitude.at(port).get();
+ }
+
+ void set_constant(const std::complex<double> constant, const size_t port)
+ {
+ set_property<double>(PROP_KEY_CONSTANT_I, constant.real(), port);
+ set_property<double>(PROP_KEY_CONSTANT_Q, constant.imag(), port);
+ }
+
+ std::complex<double> get_constant(const size_t port) const
+ {
+ return std::complex<double>(
+ _prop_constant_i.at(port).get(), _prop_constant_q.at(port).get());
+ }
+
+ void set_sine_phase_increment(const double phase_inc, const size_t port)
+ {
+ set_property<double>(PROP_KEY_SINE_PHASE_INC, phase_inc, port);
+ }
+
+ double get_sine_phase_increment(const size_t port) const
+ {
+ return _prop_phase_inc.at(port).get();
+ }
+
+ void set_samples_per_packet(const size_t spp, const size_t port)
+ {
+ set_property<int>(PROP_KEY_SPP, uhd::narrow_cast<int>(spp), port);
+ }
+
+ size_t get_samples_per_packet(const size_t port) const
+ {
+ return _prop_spp.at(port).get();
+ }
+
+ /**************************************************************************
+ * Initialization
+ *************************************************************************/
+private:
+ void _register_props()
+ {
+ const size_t num_outputs = get_num_output_ports();
+ _prop_enable.reserve(num_outputs);
+ _prop_waveform.reserve(num_outputs);
+ _prop_amplitude.reserve(num_outputs);
+ _prop_constant_i.reserve(num_outputs);
+ _prop_constant_q.reserve(num_outputs);
+ _prop_phase_inc.reserve(num_outputs);
+ _prop_spp.reserve(num_outputs);
+ _prop_type_out.reserve(num_outputs);
+
+ for (size_t port = 0; port < num_outputs; port++) {
+ // register edge properties
+ _prop_type_out.emplace_back(property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::OUTPUT_EDGE, port}});
+ register_property(&_prop_type_out.back());
+
+ // register user properties
+ _prop_enable.emplace_back(
+ property_t<bool>{PROP_KEY_ENABLE, false, {res_source_info::USER, port}});
+ _prop_waveform.emplace_back(property_t<int>{PROP_KEY_WAVEFORM,
+ static_cast<int>(siggen_waveform::CONSTANT),
+ {res_source_info::USER, port}});
+ _prop_amplitude.emplace_back(property_t<double>{
+ PROP_KEY_AMPLITUDE, 1.0, {res_source_info::USER, port}});
+ _prop_constant_i.emplace_back(property_t<double>{
+ PROP_KEY_CONSTANT_I, 1.0, {res_source_info::USER, port}});
+ _prop_constant_q.emplace_back(property_t<double>{
+ PROP_KEY_CONSTANT_Q, 1.0, {res_source_info::USER, port}});
+ _prop_phase_inc.emplace_back(property_t<double>{
+ PROP_KEY_SINE_PHASE_INC, 1.0, {res_source_info::USER, port}});
+ _prop_spp.emplace_back(property_t<int>{
+ PROP_KEY_SPP, DEFAULT_SPP, {res_source_info::USER, port}});
+
+ register_property(&_prop_enable.back(), [this, port]() {
+ _siggen_reg_iface.poke32(REG_ENABLE_OFFSET,
+ uint32_t(_prop_enable.at(port).get() ? 1 : 0),
+ port);
+ });
+ register_property(&_prop_waveform.back());
+ register_property(&_prop_amplitude.back());
+ register_property(&_prop_constant_i.back(), [this, port]() {
+ const double constant_i = _prop_constant_i.at(port).get();
+ if (constant_i < -1.0 || constant_i > 1.0) {
+ throw uhd::value_error("Constant real value must be in [-1.0, 1.0]");
+ }
+ _set_constant_register(port);
+ });
+ register_property(&_prop_constant_q.back(), [this, port]() {
+ const double constant_q = _prop_constant_q.at(port).get();
+ if (constant_q < -1.0 || constant_q > 1.0) {
+ throw uhd::value_error(
+ "Constant imaginary value must be in [-1.0, 1.0]");
+ }
+ _set_constant_register(port);
+ });
+ register_property(&_prop_phase_inc.back(), [this, port]() {
+ const double phase_inc = _prop_phase_inc.at(port).get();
+ if (phase_inc < (-M_PI) || phase_inc > (M_PI)) {
+ throw uhd::value_error(
+ "Phase increment value must be in [-pi, pi]");
+ }
+ const int16_t phase_inc_scaled_rads_fp =
+ clamp<int16_t>((phase_inc / M_PI) * 8192.0);
+ _siggen_reg_iface.poke32(
+ REG_PHASE_INC_OFFSET, phase_inc_scaled_rads_fp & 0xffff, port);
+ });
+ register_property(&_prop_spp.back(), [this, port]() {
+ const uint32_t spp = _prop_spp.at(port).get();
+ RFNOC_LOG_TRACE("Setting samples per packet to " << words_per_pkt
+ << " on chan " << chan);
+ _siggen_reg_iface.poke32(REG_SPP_OFFSET, spp, port);
+ });
+
+ add_property_resolver({&_prop_waveform.back(), &_prop_amplitude.back()},
+ {&_prop_amplitude.back()},
+ [this, port]() {
+ // Range check the waveform and amplitude properties.
+ // If either are out of range, throw an exception and
+ // do not set any registers.
+ const int waveform_val = _prop_waveform.at(port).get();
+ const int low_limit = static_cast<int>(siggen_waveform::CONSTANT);
+ const int high_limit = static_cast<int>(siggen_waveform::NOISE);
+ if (waveform_val < low_limit || waveform_val > high_limit) {
+ throw uhd::value_error("Waveform value must be in ["
+ + std::to_string(low_limit) + ", "
+ + std::to_string(high_limit) + "]");
+ }
+ const double amplitude = _prop_amplitude.at(port).get();
+ if (amplitude < 0.0 || amplitude > 1.0) {
+ throw uhd::value_error("Amplitude value must be in [0.0, 1.0]");
+ }
+
+ // Set the waveform register appropriately.
+ _siggen_reg_iface.poke32(REG_WAVEFORM_OFFSET, waveform_val, port);
+
+ // Now set the other registers based on the waveform and
+ // the desired amplitude.
+ siggen_waveform waveform = static_cast<siggen_waveform>(waveform_val);
+ switch (waveform) {
+ case siggen_waveform::CONSTANT:
+ // The amplitude is fixed at 1 in constant mode.
+ _prop_amplitude.at(port).set(1.0);
+ _set_gain_register(1.0, port);
+ break;
+ case siggen_waveform::SINE_WAVE: {
+ // Set the phasor to the appropriate amplitude value and
+ // fix the gain to 1.
+
+ // The CORDIC IP scales the value written to the Cartesian
+ // coordinate register (i.e., the phasor that is rotated to
+ // generate the sinusoid) by this value, so we pre-scale the
+ // input value before writing. See the comment in the
+ // rfnoc_block_siggen_regs.vh header file for the derivation
+ // of this value.
+ constexpr double cordic_scale_value = 1.164435344782938;
+ _set_cartesian_register(amplitude / cordic_scale_value, port);
+ _set_gain_register(1.0, port);
+ break;
+ }
+ case siggen_waveform::NOISE:
+ // Use the gain register to set the gain of the random noise
+ // signal.
+ _set_gain_register(amplitude, port);
+ break;
+ }
+ });
+
+ add_property_resolver(
+ {&_prop_spp.back(),
+ get_mtu_prop_ref({res_source_info::OUTPUT_EDGE, port})},
+ {&_prop_spp.back()},
+ [this, port]() {
+ // MTU is max payload size, header with timestamp is already
+ // accounted for
+ int spp = _prop_spp.at(port).get();
+ const int mtu =
+ static_cast<int>(get_mtu({res_source_info::OUTPUT_EDGE, port}));
+ const int mtu_samps =
+ mtu
+ / uhd::convert::get_bytes_per_item(_prop_type_out.at(port).get());
+ if (spp > mtu_samps) {
+ RFNOC_LOG_WARNING("spp value " << spp << " exceeds MTU of " << mtu
+ << "! Coercing to " << mtu_samps);
+ spp = mtu_samps;
+ }
+ if (spp <= 0) {
+ spp = DEFAULT_SPP;
+ RFNOC_LOG_WARNING(
+ "spp must be greater than zero! Coercing to " << spp);
+ }
+ _prop_spp.at(port).set(spp);
+ });
+
+ // add resolver for type
+ add_property_resolver({&_prop_type_out.back()},
+ {&_prop_type_out.back()},
+ [this, port]() { _prop_type_out.at(port).set(IO_TYPE_SC16); });
+ }
+ }
+
+ void _set_constant_register(const size_t port)
+ {
+ const int16_t constant_i_fp =
+ clamp<int16_t>(_prop_constant_i.at(port).get() * 32768.0);
+ const int16_t constant_q_fp =
+ clamp<int16_t>(_prop_constant_q.at(port).get() * 32768.0);
+ const uint32_t constant_reg_value = (uint32_t(constant_i_fp) << 16)
+ | (uint32_t(constant_q_fp) & 0xffff);
+
+ _siggen_reg_iface.poke32(REG_CONSTANT_OFFSET, constant_reg_value, port);
+ }
+
+ void _set_gain_register(const double gain, const size_t port)
+ {
+ const int16_t gain_fp = clamp<int16_t>(gain * 32768.0);
+ _siggen_reg_iface.poke32(REG_GAIN_OFFSET, gain_fp, port);
+ }
+
+ void _set_cartesian_register(const double amplitude, const size_t port)
+ {
+ // The rotator that rotates the phasor to generate the sinusoidal
+ // data has an initial phase offset which is impossible to predict.
+ // Thus, the Cartesian parameter is largely immaterial, as long as
+ // the phasor's amplitude matchines with the client has specified.
+ // For simplicity, the Cartesian parameter is chosen to have a real
+ // (X) component of 0.0 and an imaginary (Y) component of the desired
+ // amplitude.
+ const int16_t cartesian_i_fp = clamp<int16_t>(amplitude * 32767.0);
+
+ // Bits 31:16 represent the imaginary component (the pre-scaled
+ // fixed point amplitude), while bits 15:0 represents the real
+ // component (which are zeroed).
+ const uint32_t cartesian_reg_value = (uint32_t(cartesian_i_fp) << 16);
+ _siggen_reg_iface.poke32(REG_CARTESIAN_OFFSET, cartesian_reg_value, port);
+ }
+
+ /**************************************************************************
+ * Attributes
+ *************************************************************************/
+ std::vector<property_t<bool>> _prop_enable;
+ std::vector<property_t<int>> _prop_waveform;
+ std::vector<property_t<double>> _prop_amplitude;
+ std::vector<property_t<double>> _prop_constant_i;
+ std::vector<property_t<double>> _prop_constant_q;
+ std::vector<property_t<double>> _prop_phase_inc;
+ std::vector<property_t<int>> _prop_spp;
+ std::vector<property_t<std::string>> _prop_type_out;
+
+ /**************************************************************************
+ * Register interface
+ *************************************************************************/
+ multichan_register_iface _siggen_reg_iface;
+};
+
+UHD_RFNOC_BLOCK_REGISTER_DIRECT(
+ siggen_block_control, SIGGEN_BLOCK, "SigGen", CLOCK_KEY_GRAPH, "bus_clk")