aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2020-04-14 16:23:59 -0500
committerWade Fife <wade.fife@ettus.com>2020-04-14 16:37:43 -0500
commitd386c750074f6da4ab86038e2c30a3fe6e0f9d47 (patch)
treee4258b2744e24bf6e829910e66c93a74b8d7603a /host
parenta8c4f021277cf3b0a0897fa9da0252541512f3a6 (diff)
downloaduhd-d386c750074f6da4ab86038e2c30a3fe6e0f9d47.tar.gz
uhd-d386c750074f6da4ab86038e2c30a3fe6e0f9d47.tar.bz2
uhd-d386c750074f6da4ab86038e2c30a3fe6e0f9d47.zip
rfnoc: Add RFNoC fosphor block
Diffstat (limited to 'host')
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt1
-rw-r--r--host/include/uhd/rfnoc/blocks/fosphor.yml56
-rw-r--r--host/include/uhd/rfnoc/defaults.hpp2
-rw-r--r--host/include/uhd/rfnoc/fosphor_block_control.hpp383
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/fosphor_block_control.cpp418
6 files changed, 861 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
index 6435ec2a6..098c79562 100644
--- a/host/include/uhd/rfnoc/CMakeLists.txt
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -36,6 +36,7 @@ UHD_INSTALL(FILES
dmafifo_block_control.hpp
fft_block_control.hpp
fir_filter_block_control.hpp
+ fosphor_block_control.hpp
null_block_control.hpp
radio_control.hpp
diff --git a/host/include/uhd/rfnoc/blocks/fosphor.yml b/host/include/uhd/rfnoc/blocks/fosphor.yml
new file mode 100644
index 000000000..d803dc602
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/fosphor.yml
@@ -0,0 +1,56 @@
+schema: rfnoc_modtool_args
+module_name: fosphor
+version: 1.0
+rfnoc_version: 1.0
+chdr_width: 64
+noc_id: 0x666F0000
+
+clocks:
+ - name: rfnoc_chdr
+ freq: "[]"
+ - name: rfnoc_ctrl
+ freq: "[]"
+ - name: ce
+ freq: "[]"
+
+control:
+ sw_iface: nocscript
+ fpga_iface: ctrlport
+ interface_direction: slave
+ fifo_depth: 32
+ clk_domain: ce
+ ctrlport:
+ byte_mode: False
+ timed: False
+ has_status: False
+
+data:
+ fpga_iface: axis_data
+ clk_domain: ce
+ inputs:
+ fft_in:
+ item_width: 32
+ nipc: 1
+ info_fifo_depth: 32
+ payload_fifo_depth: 32
+ format: sc16
+ mdata_sig: ~
+ outputs:
+ hist:
+ item_width: 8
+ nipc: 4
+ info_fifo_depth: 32
+ payload_fifo_depth: 32
+ format: u8
+ mdata_sig: ~
+ wf:
+ item_width: 8
+ nipc: 4
+ info_fifo_depth: 32
+ payload_fifo_depth: 32
+ format: u8
+ mdata_sig: ~
+
+registers:
+
+properties:
diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp
index bc97fd9f5..38ae57242 100644
--- a/host/include/uhd/rfnoc/defaults.hpp
+++ b/host/include/uhd/rfnoc/defaults.hpp
@@ -30,6 +30,7 @@ static const std::string NODE_ID_SEP("SEP");
using io_type_t = std::string;
static const io_type_t IO_TYPE_SC16 = "sc16";
+static const io_type_t IO_TYPE_U8 = "u8";
static const std::string ACTION_KEY_STREAM_CMD("stream_cmd");
static const std::string ACTION_KEY_RX_EVENT("rx_event");
@@ -75,5 +76,6 @@ static const noc_id_t RADIO_BLOCK = 0x12AD1000;
static const noc_id_t DUC_BLOCK = 0xD0C00000;
static const noc_id_t DDC_BLOCK = 0xDDC00000;
static const noc_id_t FIR_FILTER_BLOCK = 0xf1120000;
+static const noc_id_t FOSPHOR_BLOCK = 0x666F0000;
}} // namespace uhd::rfnoc
diff --git a/host/include/uhd/rfnoc/fosphor_block_control.hpp b/host/include/uhd/rfnoc/fosphor_block_control.hpp
new file mode 100644
index 000000000..965b733a7
--- /dev/null
+++ b/host/include/uhd/rfnoc/fosphor_block_control.hpp
@@ -0,0 +1,383 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/config.hpp>
+#include <uhd/rfnoc/noc_block_base.hpp>
+
+namespace uhd { namespace rfnoc {
+
+enum class fosphor_waterfall_mode { MAX_HOLD, AVERAGE };
+enum class fosphor_waterfall_predivision_ratio {
+ RATIO_1_1,
+ RATIO_1_8,
+ RATIO_1_64,
+ RATIO_1_256
+};
+
+/*!
+ * Fosphor Control Class
+ *
+ * The Fosphor Block is an RFNoC block that accepts FFT data as signed
+ * complex 16-bit data and produces two streams of eight-bit data, a
+ * stream of histogram data and a stream of waterfall data.
+ *
+ * \section Histogram
+ *
+ * Each time the Fosphor block receives an FFT input packet, the power values
+ * in each of the N frequency bins are quantized into one of 64 power bins
+ * (X axis represents individual FFT frequency bins; Y axis represents the
+ * power bins):
+ *
+ * 63 .
+ * : . .
+ * : . . . . . .
+ * 0 . . . . . . . . . . . . . . . . . . . .
+ * 0 1 2 3 4 5 - - - - - - - - - - - - - - - - - - - - - - N-1
+ *
+ * Each time an FFT power value is quantized to a bin, the bin count
+ * is increased by one (illustrated by a '+'):
+ *
+ * 63 +
+ * : + +
+ * : + + + + + +
+ * 0 + + + + + + + + + + + + + + + + + + + +
+ * 0 1 2 3 4 5 - - - - - - - - - - - - - - - - - - - - - - N-1
+ *
+ * As more FFT packets are received, the counts in each bin accumulate.
+ * Over time, the count in the 'closest' power bin to each sample in the FFT
+ * accumulates at the highest rate. However, adjacent power bins' counts may
+ * increase due to quantization noise and variances in the input FFT signal
+ * (highest counts illustrated by '*', followed by '+' and '.'):
+ *
+ * 63 . * +
+ * : . . . + * . * +
+ * : + + . . + + . + * * + + + * + * + + * * . + . + + .
+ * 0 * * * * * * * * + + * * * + + * * + + * * * * * *
+ * 0 1 2 3 4 5 - - - - - - - - - - - - - - - - - - - - - - N-1
+ *
+ * The Fosphor block also calculates the average power level and maximum
+ * power level encountered in each FFT frequency bin. The rate at which
+ * the accumulated counts, average power level, and maximum power level
+ * values rise and fall over time is configurable.
+ *
+ * An instance of histogram data output consists of 66 packets:
+ *
+ * * 64 packets, one per quantized power level, of N values, representing the
+ * accumulated count for each frequency bin for that particular quantized
+ * power level;
+ * * One packet of N values, representing the average power level in each
+ * frequency bin; and
+ * * One packet of N values, representing the maximum power level in each
+ * frequency bin.
+ *
+ * \section Waterfall
+ *
+ * The waterfall stream consists of history data of either the average or
+ * maximum power level values in each bin, depending on the selected waterfall
+ * mode. In max hold mode, each waterfall packet consists of N values,
+ * representing the maximum power level in each frequency bin. The rate
+ * that packets are produced relative to the number of input FFT packets is
+ * configurable via the waterfall decimation parameter.
+ *
+ * In average mode, each waterfall packet consists of N values, representing
+ * the _sum_ of the average power level in each frequency bin accumulated
+ * between packets. (Thus, if the decimation rate is increased, the values
+ * returned are higher than if the decimation rate is decreased.) The
+ * waterfall predivision ratio parameter can be used to scale the values
+ * prior to accumulation to counteract this effect.
+ *
+ * These streams are intended to be inputs to the GNU Radio Fosphor
+ * display block, which renders the streams in a entertaining graphical
+ * format.
+ */
+class UHD_API fosphor_block_control : public noc_block_base
+{
+public:
+ RFNOC_DECLARE_BLOCK(fosphor_block_control)
+
+ // Block registers
+ static const uint32_t REG_ENABLE_ADDR;
+ static const uint32_t REG_CLEAR_ADDR;
+ static const uint32_t REG_RANDOM_ADDR;
+ static const uint32_t REG_DECIM_ADDR;
+ static const uint32_t REG_OFFSET_ADDR;
+ static const uint32_t REG_SCALE_ADDR;
+ static const uint32_t REG_TRISE_ADDR;
+ static const uint32_t REG_TDECAY_ADDR;
+ static const uint32_t REG_ALPHA_ADDR;
+ static const uint32_t REG_EPSILON_ADDR;
+ static const uint32_t REG_WF_CTRL_ADDR;
+ static const uint32_t REG_WF_DECIM_ADDR;
+
+ /*! Set the histogram stream enable flag
+ *
+ * Enables or disables the stream of histogram data from the block.
+ *
+ * \param enable_histogram Histogram stream enable/disable flag
+ */
+ virtual void set_enable_histogram(const bool enable_histogram) = 0;
+
+ /*! Get the histogram stream enable flag
+ *
+ * Returns the current histogram enable value.
+ *
+ * \returns Histogram stream enable/disable flag
+ */
+ virtual bool get_enable_histogram() const = 0;
+
+ /*! Set the waterfall stream enable flag
+ *
+ * Enables or disables the stream of waterfall data from the block.
+ *
+ * \param enable_waterfall Histogram stream enable/disable flag
+ */
+ virtual void set_enable_waterfall(const bool enable_waterfall) = 0;
+
+ /*! Get the waterfall stream enable flag
+ *
+ * Returns the current waterfall enable value.
+ *
+ * \returns Histogram stream enable/disable flag
+ */
+ virtual bool get_enable_waterfall() const = 0;
+
+ /*! Clear the Fosphor block's stored history
+ *
+ * Clears the accumulated history in the Fosphor block, resetting
+ * average and max hold values.
+ */
+ virtual void clear_history() = 0;
+
+ /*! Set the dither enable flag
+ *
+ * Enables or disables dithering. Dithering adds quantization error
+ * to the incoming signal.
+ *
+ * \param enable_dither Dither enable/disable flag
+ */
+ virtual void set_enable_dither(const bool enable_dither) = 0;
+
+ /*! Get the dither enable flag
+ *
+ * Returns the current dither enable value.
+ *
+ * \returns Dither enable/disable flag
+ */
+ virtual bool get_enable_dither() const = 0;
+
+ /*! Set the noise enable flag
+ *
+ * Enables or disables the addition of random noise to the incoming
+ * signal.
+ *
+ * \param enable_noise Noise enable/disable flag
+ */
+ virtual void set_enable_noise(const bool enable_noise) = 0;
+
+ /*! Get the noise enable flag
+ *
+ * Returns the current noise enable value.
+ *
+ * \returns Noise enable/disable flag
+ */
+ virtual bool get_enable_noise() const = 0;
+
+ /*! Set the histogram decimation factor
+ *
+ * Sets the ratio of histogram outputs to FFT packet inputs.
+ * For every \p decimation FFT input packets, one histogram
+ * output cluster (64 histogram packets, plus a maximum and
+ * average values packet) is produced. The minimum value for
+ * \p decimation is 2.
+ *
+ * \param decimation Histogram decimation factor
+ */
+ virtual void set_histogram_decimation(const uint16_t decimation) = 0;
+
+ /*! Get the histogram decimation factor
+ *
+ * Returns the current histogram decimation factor.
+ *
+ * \returns Histogram decimation factor
+ */
+ virtual uint16_t get_histogram_decimation() const = 0;
+
+ /*! Set the histogram offset factor
+ *
+ * Sets the offset factor to apply to FFT power levels before determining
+ * the appropriate histogram bin.
+ *
+ * \param offset The histogram offset factor to apply
+ */
+ virtual void set_histogram_offset(const uint16_t offset) = 0;
+
+ /*! Get the histogram offset factor
+ *
+ * Returns the current histogram offset factor.
+ *
+ * \returns The histogram offset factor
+ */
+ virtual uint16_t get_histogram_offset() const = 0;
+
+ /*! Set the histogram scale factor
+ *
+ * Sets the scale factor to apply to FFT power levels before determining
+ * the appropriate histogram bin. The scaling factor is \p scale / 256.
+ *
+ * \param scale The histogram scale factor to apply
+ */
+ virtual void set_histogram_scale(const uint16_t scale) = 0;
+
+ /*! Get the history scale factor
+ *
+ * Returns the current histogram scale factor.
+ *
+ * \returns The histogram scale factor
+ */
+ virtual uint16_t get_histogram_scale() const = 0;
+
+ /*! Set the histogram rise rate factor
+ *
+ * Sets the rate at which the hit count in each frequency and power bin
+ * increases when accumulating (i.e., there are hits in the particular
+ * bin). The higher the value, the more quickly the values increase,
+ * leading to a phosphorescent-like effect on the Fosphor display similar
+ * to the gradual illumination of a CRT display in the area where the
+ * electron beam is pointing.
+ *
+ * \param rise_rate The histogram rise rate factor to apply
+ */
+ virtual void set_histogram_rise_rate(const uint16_t rise_rate) = 0;
+
+ /*! Get the histogram rise rate factor
+ *
+ * Returns the current histogram rise rate factor.
+ *
+ * \returns The histogram rise rate factor
+ */
+ virtual uint16_t get_histogram_rise_rate() const = 0;
+
+ /*! Set the histogram decay rate factor
+ *
+ * Sets the rate at which the hit count in each frequency and power bin
+ * decreases when not accumulating (i.e., there are no hits in the
+ * particular bin). The lower the value, the more slowly the values
+ * decrease, leading to a phosphorescent-like effect on the Fosphor
+ * display similar to the gradual fading of a CRT display when the
+ * electron beam is extinguished.
+ *
+ * \param decay_rate The histogram decay rate factor to apply
+ */
+ virtual void set_histogram_decay_rate(const uint16_t decay_rate) = 0;
+
+ /*! Get the histogram decay rate factor
+ *
+ * Returns the current histogram decay rate factor.
+ *
+ * \returns The histogram decay rate factor
+ */
+ virtual uint16_t get_histogram_decay_rate() const = 0;
+
+ /*! Set the power level moving average weighting
+ *
+ * Sets the weighing to be applied to the average power level value
+ * for each FFT frequency bin. The higher the value, the higher the
+ * weight is given to older samples (and thus the more slowly the average
+ * values change over time in each bin).
+ *
+ * \param alpha The power level moving average weighting to apply
+ */
+ virtual void set_spectrum_alpha(const uint16_t alpha) = 0;
+
+ /*! Get the power level moving average weighting
+ *
+ * Returns the weighting that is applied to older samples when calculating
+ * the average power level for each FFT frequency bin.
+ *
+ * \returns The power level moving average weighting
+ */
+ virtual uint16_t get_spectrum_alpha() const = 0;
+
+ /*! Set the maximum hold decay rate
+ *
+ * Sets the rate at which the maximum value for each FFT frequency
+ * bin decays. The higher the value, the faster the decay rate.
+ * A value of 0 retains the maximum values indefinitely.
+ *
+ * \param epsilon The histogram scale factor to apply
+ */
+ virtual void set_spectrum_max_hold_decay(const uint16_t epsilon) = 0;
+
+ /*! Get the maximum hold decay rate
+ *
+ * Returns the rate at which the maximum value for each FFT frequency
+ * bin decays.
+ *
+ * \returns The maximum hold decay rate
+ */
+ virtual uint16_t get_spectrum_max_hold_decay() const = 0;
+
+ /*! Set the waterfall predivision ratio
+ *
+ * Sets the scaling factor applied to waterfall values.
+ *
+ * \param waterfall_predivision The waterfall predivision ratio to apply
+ */
+ virtual void set_waterfall_predivision(
+ const fosphor_waterfall_predivision_ratio waterfall_predivision) = 0;
+
+ /*! Get the waterfall predivision ratio
+ *
+ * Returns the current waterfall predivision ratio.
+ *
+ * \returns The waterfall predivision ratio
+ */
+ virtual fosphor_waterfall_predivision_ratio get_waterfall_predivision() const = 0;
+
+ /*! Set the waterfall mode setting
+ *
+ * Sets the source of the waterfall history data. When \p waterfall_mode
+ * is set to `MAX_HOLD`, the waterfall data is comprised of the max
+ * power values from each FFT frequency bin. When \p waterfall_mode is set
+ * to `AVERAGE`, the waterfall data is comprised of the accumulated
+ * average value from each FFT frequency bin between waterfall output
+ * packets.
+ *
+ * \param waterfall_mode The waterfall mode setting
+ */
+ virtual void set_waterfall_mode(const fosphor_waterfall_mode waterfall_mode) = 0;
+
+ /*! Get the waterfall mode setting
+ *
+ * Returns the current waterfall mode setting.
+ *
+ * \returns The waterfall mode setting
+ */
+ virtual fosphor_waterfall_mode get_waterfall_mode() const = 0;
+
+ /*! Set the waterfall decimation factor
+ *
+ * Sets the ratio of waterfall outputs to FFT packet inputs.
+ * For every \p waterfall_decimation FFT input packets, one waterfall
+ * output packet is produced. The minimum value for
+ * \p waterfall_decimation is 2.
+ *
+ * \param waterfall_decimation The waterfall decimation factor to apply
+ */
+ virtual void set_waterfall_decimation(const uint16_t waterfall_decimation) = 0;
+
+ /*! Get the histogram decimation factor
+ *
+ * Returns the current waterfall decimation factor.
+ *
+ * \returns The waterfall decimation factor
+ */
+ virtual uint16_t get_waterfall_decimation() const = 0;
+};
+
+}} // namespace uhd::rfnoc
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index 4edfe4009..6881a57e8 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -46,6 +46,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/dmafifo_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fft_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fir_filter_block_control.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/fosphor_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/null_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp
)
diff --git a/host/lib/rfnoc/fosphor_block_control.cpp b/host/lib/rfnoc/fosphor_block_control.cpp
new file mode 100644
index 000000000..6bf621982
--- /dev/null
+++ b/host/lib/rfnoc/fosphor_block_control.cpp
@@ -0,0 +1,418 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/exception.hpp>
+#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/fosphor_block_control.hpp>
+#include <uhd/rfnoc/property.hpp>
+#include <uhd/rfnoc/registry.hpp>
+#include <string>
+
+using namespace uhd::rfnoc;
+
+
+// Register offsets
+const uint32_t fosphor_block_control::REG_ENABLE_ADDR = 0x00;
+const uint32_t fosphor_block_control::REG_CLEAR_ADDR = 0x04;
+const uint32_t fosphor_block_control::REG_RANDOM_ADDR = 0x08;
+const uint32_t fosphor_block_control::REG_DECIM_ADDR = 0x0c;
+const uint32_t fosphor_block_control::REG_OFFSET_ADDR = 0x10;
+const uint32_t fosphor_block_control::REG_SCALE_ADDR = 0x14;
+const uint32_t fosphor_block_control::REG_TRISE_ADDR = 0x18;
+const uint32_t fosphor_block_control::REG_TDECAY_ADDR = 0x1c;
+const uint32_t fosphor_block_control::REG_ALPHA_ADDR = 0x20;
+const uint32_t fosphor_block_control::REG_EPSILON_ADDR = 0x24;
+const uint32_t fosphor_block_control::REG_WF_CTRL_ADDR = 0x28;
+const uint32_t fosphor_block_control::REG_WF_DECIM_ADDR = 0x2c;
+
+// Mask bits
+constexpr uint32_t RESET_HISTORY_BIT = 0;
+constexpr uint32_t RESET_HISTORY_MASK = (1 << RESET_HISTORY_BIT);
+constexpr uint32_t RESET_CORE_BIT = 1;
+constexpr uint32_t RESET_CORE_MASK = (1 << RESET_CORE_BIT);
+
+constexpr uint32_t HISTOGRAM_ENABLE_BIT = 0;
+constexpr uint32_t HISTOGRAM_ENABLE_MASK = (1 << HISTOGRAM_ENABLE_BIT);
+constexpr uint32_t WATERFALL_ENABLE_BIT = 1;
+constexpr uint32_t WATERFALL_ENABLE_MASK = (1 << WATERFALL_ENABLE_BIT);
+
+constexpr uint32_t DITHER_ENABLE_BIT = 0;
+constexpr uint32_t DITHER_ENABLE_MASK = (1 << DITHER_ENABLE_BIT);
+constexpr uint32_t NOISE_ENABLE_BIT = 1;
+constexpr uint32_t NOISE_ENABLE_MASK = (1 << NOISE_ENABLE_BIT);
+
+constexpr uint32_t WATERFALL_MODE_BIT = 7;
+constexpr uint32_t WATERFALL_MODE_MASK = (1 << WATERFALL_MODE_BIT);
+constexpr uint32_t PREDIV_RATIO_MASK = (1 << 0) | (1 << 1);
+
+// User property names
+const char* const PROP_KEY_ENABLE_HISTOGRAM = "enable_histogram";
+const char* const PROP_KEY_ENABLE_WATERFALL = "enable_waterfall";
+const char* const PROP_KEY_CLEAR_HISTORY = "clear_history";
+const char* const PROP_KEY_ENABLE_DITHER = "enable_dither";
+const char* const PROP_KEY_ENABLE_NOISE = "enable_noise";
+const char* const PROP_KEY_HIST_DECIMATION = "hist_decimation";
+const char* const PROP_KEY_OFFSET = "offset";
+const char* const PROP_KEY_SCALE = "scale";
+const char* const PROP_KEY_RISE_TIME = "trise";
+const char* const PROP_KEY_DECAY_TIME = "tdecay";
+const char* const PROP_KEY_ALPHA = "alpha";
+const char* const PROP_KEY_EPSILON = "epsilon";
+const char* const PROP_KEY_WF_PREDIVISION_RATIO = "wf_predivision_ratio";
+const char* const PROP_KEY_WF_MODE = "wf_mode";
+const char* const PROP_KEY_WF_DECIMATION = "wf_decimation";
+
+// Edge property details
+constexpr uint32_t HISTOGRAM_PORT = 0;
+constexpr uint32_t WATERFALL_PORT = 1;
+
+
+class fosphor_block_control_impl : public fosphor_block_control
+{
+public:
+ RFNOC_BLOCK_CONSTRUCTOR(fosphor_block_control)
+ {
+ // reset the core upon block construction
+ this->regs().poke32(REG_CLEAR_ADDR, RESET_CORE_MASK);
+ _register_props();
+ }
+
+ void set_enable_histogram(const bool enable_histogram)
+ {
+ set_property<bool>(PROP_KEY_ENABLE_HISTOGRAM, enable_histogram);
+ }
+
+ bool get_enable_histogram() const
+ {
+ return _prop_enable_histogram.get();
+ }
+
+ void set_enable_waterfall(const bool enable_waterfall)
+ {
+ set_property<bool>(PROP_KEY_ENABLE_WATERFALL, enable_waterfall);
+ }
+
+ bool get_enable_waterfall() const
+ {
+ return _prop_enable_waterfall.get();
+ }
+
+ void clear_history()
+ {
+ set_property<bool>(PROP_KEY_CLEAR_HISTORY, true);
+ }
+
+ void set_enable_dither(const bool enable_dither)
+ {
+ set_property<bool>(PROP_KEY_ENABLE_DITHER, enable_dither);
+ }
+
+ bool get_enable_dither() const
+ {
+ return _prop_enable_dither.get();
+ }
+
+ void set_enable_noise(const bool enable_noise)
+ {
+ set_property<bool>(PROP_KEY_ENABLE_NOISE, enable_noise);
+ }
+
+ bool get_enable_noise() const
+ {
+ return _prop_enable_noise.get();
+ }
+
+ void set_histogram_decimation(const uint16_t decimation)
+ {
+ set_property<int>(PROP_KEY_HIST_DECIMATION, decimation);
+ }
+
+ uint16_t get_histogram_decimation() const
+ {
+ return _prop_hist_decimation.get();
+ }
+
+ void set_histogram_offset(const uint16_t offset)
+ {
+ set_property<int>(PROP_KEY_OFFSET, offset);
+ }
+
+ uint16_t get_histogram_offset() const
+ {
+ return _prop_offset.get();
+ }
+
+ void set_histogram_scale(const uint16_t scale)
+ {
+ set_property<int>(PROP_KEY_SCALE, scale);
+ }
+
+ uint16_t get_histogram_scale() const
+ {
+ return _prop_scale.get();
+ }
+
+ void set_histogram_rise_rate(const uint16_t rise_rate)
+ {
+ set_property<int>(PROP_KEY_RISE_TIME, rise_rate);
+ }
+
+ uint16_t get_histogram_rise_rate() const
+ {
+ return _prop_trise.get();
+ }
+
+ void set_histogram_decay_rate(const uint16_t decay_rate)
+ {
+ set_property<int>(PROP_KEY_DECAY_TIME, decay_rate);
+ }
+
+ uint16_t get_histogram_decay_rate() const
+ {
+ return _prop_tdecay.get();
+ }
+
+ void set_spectrum_alpha(const uint16_t alpha)
+ {
+ set_property<int>(PROP_KEY_ALPHA, alpha);
+ }
+
+ uint16_t get_spectrum_alpha() const
+ {
+ return _prop_alpha.get();
+ }
+
+ void set_spectrum_max_hold_decay(const uint16_t epsilon)
+ {
+ set_property<int>(PROP_KEY_EPSILON, epsilon);
+ }
+
+ uint16_t get_spectrum_max_hold_decay() const
+ {
+ return _prop_epsilon.get();
+ }
+
+ void set_waterfall_predivision(
+ const fosphor_waterfall_predivision_ratio waterfall_predivision)
+ {
+ set_property<int>(
+ PROP_KEY_WF_PREDIVISION_RATIO, static_cast<int>(waterfall_predivision));
+ }
+
+ fosphor_waterfall_predivision_ratio get_waterfall_predivision() const
+ {
+ return static_cast<fosphor_waterfall_predivision_ratio>(
+ _prop_wf_prediv_ratio.get());
+ }
+
+ void set_waterfall_mode(const fosphor_waterfall_mode waterfall_mode)
+ {
+ set_property<int>(PROP_KEY_WF_MODE, static_cast<int>(waterfall_mode));
+ }
+
+ fosphor_waterfall_mode get_waterfall_mode() const
+ {
+ return static_cast<fosphor_waterfall_mode>(_prop_wf_mode.get());
+ }
+
+ void set_waterfall_decimation(const uint16_t waterfall_decimation)
+ {
+ set_property<int>(PROP_KEY_WF_DECIMATION, waterfall_decimation);
+ }
+
+ uint16_t get_waterfall_decimation() const
+ {
+ return _prop_wf_decim.get();
+ }
+
+ /**************************************************************************
+ * Initialization
+ *************************************************************************/
+private:
+ void _register_props()
+ {
+ // register user properties
+ register_property(&_prop_enable_histogram, [this]() { _program_enables(); });
+ register_property(&_prop_enable_waterfall, [this]() { _program_enables(); });
+ register_property(&_prop_clear_history,
+ [this]() { this->regs().poke32(REG_CLEAR_ADDR, RESET_HISTORY_MASK); });
+ register_property(
+ &_prop_enable_dither, [this]() { _program_randomness_enables(); });
+ register_property(
+ &_prop_enable_noise, [this]() { _program_randomness_enables(); });
+ register_property(&_prop_hist_decimation, [this]() {
+ int decim = _prop_hist_decimation.get();
+ if (decim < 2 || decim > 1024) {
+ throw uhd::value_error(
+ "Histogram decimation value must be in [2, 1024]");
+ }
+ this->regs().poke32(REG_DECIM_ADDR, uint32_t(decim - 2));
+ });
+ register_property(&_prop_offset, [this]() {
+ int offset = _prop_offset.get();
+ if (offset < 0 || offset > 65535) {
+ throw uhd::value_error("Offset value must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_OFFSET_ADDR, uint32_t(offset));
+ });
+ register_property(&_prop_scale, [this]() {
+ int scale = _prop_scale.get();
+ if (scale < 0 || scale > 65535) {
+ throw uhd::value_error("Scale value must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_SCALE_ADDR, uint32_t(scale));
+ });
+ register_property(&_prop_trise, [this]() {
+ int trise = _prop_trise.get();
+ if (trise < 0 || trise > 65535) {
+ throw uhd::value_error("Rise rate value must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_TRISE_ADDR, uint32_t(trise));
+ });
+ register_property(&_prop_tdecay, [this]() {
+ int tdecay = _prop_tdecay.get();
+ if (tdecay < 0 || tdecay > 65535) {
+ throw uhd::value_error("Decay rate value must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_TDECAY_ADDR, uint32_t(tdecay));
+ });
+ register_property(&_prop_alpha, [this]() {
+ int alpha = _prop_alpha.get();
+ if (alpha < 0 || alpha > 65535) {
+ throw uhd::value_error("Alpha value must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_ALPHA_ADDR, uint32_t(alpha));
+ });
+ register_property(&_prop_epsilon, [this]() {
+ int epsilon = _prop_epsilon.get();
+ if (epsilon < 0 || epsilon > 65535) {
+ throw uhd::value_error("Max hold decay rate must be in [0, 65535]");
+ }
+ this->regs().poke32(REG_EPSILON_ADDR, uint32_t(epsilon));
+ });
+ register_property(&_prop_wf_prediv_ratio, [this]() {
+ int prediv_ratio = _prop_wf_prediv_ratio.get();
+ if (prediv_ratio
+ < static_cast<int>(fosphor_waterfall_predivision_ratio::RATIO_1_1)
+ || prediv_ratio > static_cast<int>(
+ fosphor_waterfall_predivision_ratio::RATIO_1_256)) {
+ throw uhd::value_error(
+ "Waterfall predivision ratio value must be in [0, 3]");
+ }
+ _program_waterfall_mode();
+ });
+ register_property(&_prop_wf_mode, [this]() {
+ int wf_mode = _prop_wf_mode.get();
+ if (wf_mode < static_cast<int>(fosphor_waterfall_mode::MAX_HOLD)
+ || wf_mode > static_cast<int>(fosphor_waterfall_mode::AVERAGE)) {
+ throw uhd::value_error("Waterfall mode value must be 0 or 1");
+ }
+ _program_waterfall_mode();
+ });
+ register_property(&_prop_wf_decim, [this]() {
+ int wf_decim = _prop_wf_decim.get();
+ if (wf_decim < 2 || wf_decim > 257) {
+ throw uhd::value_error(
+ "Waterfall decimation value must be in [2, 257]");
+ }
+ this->regs().poke32(REG_WF_DECIM_ADDR, uint32_t(wf_decim - 2));
+ });
+
+ // register edge properties
+ register_property(&_prop_type_in);
+ register_property(&_prop_type_out_histogram);
+ register_property(&_prop_type_out_wf);
+
+ // add resolvers for type
+ add_property_resolver({&_prop_type_in}, {&_prop_type_in}, [this]() {
+ _prop_type_in.set(IO_TYPE_SC16);
+ });
+ add_property_resolver({&_prop_type_out_histogram},
+ {&_prop_type_out_histogram},
+ [this]() { _prop_type_out_histogram.set(IO_TYPE_U8); });
+ add_property_resolver({&_prop_type_out_wf}, {&_prop_type_out_wf}, [this]() {
+ _prop_type_out_wf.set(IO_TYPE_U8);
+ });
+ }
+
+ void _program_enables()
+ {
+ uint32_t reg_value = this->regs().peek32(REG_ENABLE_ADDR)
+ & ~(HISTOGRAM_ENABLE_MASK | WATERFALL_ENABLE_MASK);
+ uint32_t histogram_enable_bit =
+ (_prop_enable_histogram.get()) ? HISTOGRAM_ENABLE_MASK : 0;
+ uint32_t waterfall_enable_bit =
+ (_prop_enable_waterfall.get()) ? WATERFALL_ENABLE_MASK : 0;
+ this->regs().poke32(
+ REG_ENABLE_ADDR, reg_value | histogram_enable_bit | waterfall_enable_bit);
+ }
+
+ void _program_randomness_enables()
+ {
+ uint32_t reg_value = this->regs().peek32(REG_RANDOM_ADDR)
+ & ~(DITHER_ENABLE_MASK | NOISE_ENABLE_MASK);
+ uint32_t dither_enable_bit = (_prop_enable_dither.get()) ? DITHER_ENABLE_MASK : 0;
+ uint32_t noise_enable_bit = (_prop_enable_noise.get()) ? NOISE_ENABLE_MASK : 0;
+ this->regs().poke32(
+ REG_RANDOM_ADDR, reg_value | dither_enable_bit | noise_enable_bit);
+ }
+
+ void _program_waterfall_mode()
+ {
+ uint32_t reg_value = this->regs().peek32(REG_WF_CTRL_ADDR)
+ & ~(WATERFALL_MODE_MASK | PREDIV_RATIO_MASK);
+ int prediv_ratio = _prop_wf_prediv_ratio.get();
+ int wf_mode = _prop_wf_mode.get();
+ uint32_t wf_mode_bits = (wf_mode << WATERFALL_MODE_BIT) | prediv_ratio;
+ this->regs().poke32(REG_WF_CTRL_ADDR, reg_value | wf_mode_bits);
+ }
+
+ /**************************************************************************
+ * Attributes
+ *************************************************************************/
+ property_t<std::string> _prop_type_in = property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE}};
+ property_t<std::string> _prop_type_out_histogram = property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_U8, {res_source_info::OUTPUT_EDGE, HISTOGRAM_PORT}};
+ property_t<std::string> _prop_type_out_wf = property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_U8, {res_source_info::OUTPUT_EDGE, WATERFALL_PORT}};
+
+ property_t<bool> _prop_enable_histogram =
+ property_t<bool>{PROP_KEY_ENABLE_HISTOGRAM, true, {res_source_info::USER}};
+ property_t<bool> _prop_enable_waterfall =
+ property_t<bool>{PROP_KEY_ENABLE_WATERFALL, true, {res_source_info::USER}};
+ property_t<bool> _prop_clear_history =
+ property_t<bool>{PROP_KEY_CLEAR_HISTORY, false, {res_source_info::USER}};
+ property_t<bool> _prop_enable_dither =
+ property_t<bool>{PROP_KEY_ENABLE_DITHER, true, {res_source_info::USER}};
+ property_t<bool> _prop_enable_noise =
+ property_t<bool>{PROP_KEY_ENABLE_NOISE, true, {res_source_info::USER}};
+ property_t<int> _prop_hist_decimation =
+ property_t<int>{PROP_KEY_HIST_DECIMATION, 2, {res_source_info::USER}};
+ property_t<int> _prop_offset =
+ property_t<int>{PROP_KEY_OFFSET, 0, {res_source_info::USER}};
+ property_t<int> _prop_scale =
+ property_t<int>{PROP_KEY_SCALE, 256, {res_source_info::USER}};
+ property_t<int> _prop_trise =
+ property_t<int>{PROP_KEY_RISE_TIME, 4096, {res_source_info::USER}};
+ property_t<int> _prop_tdecay =
+ property_t<int>{PROP_KEY_DECAY_TIME, 16384, {res_source_info::USER}};
+ property_t<int> _prop_alpha =
+ property_t<int>{PROP_KEY_ALPHA, 65280, {res_source_info::USER}};
+ property_t<int> _prop_epsilon =
+ property_t<int>{PROP_KEY_EPSILON, 1, {res_source_info::USER}};
+ property_t<int> _prop_wf_prediv_ratio = property_t<int>{PROP_KEY_WF_PREDIVISION_RATIO,
+ static_cast<int>(fosphor_waterfall_predivision_ratio::RATIO_1_1),
+ {res_source_info::USER}};
+ property_t<int> _prop_wf_mode = property_t<int>{PROP_KEY_WF_MODE,
+ static_cast<int>(fosphor_waterfall_mode::MAX_HOLD),
+ {res_source_info::USER}};
+ property_t<int> _prop_wf_decim =
+ property_t<int>{PROP_KEY_WF_DECIMATION, 8, {res_source_info::USER}};
+};
+
+UHD_RFNOC_BLOCK_REGISTER_DIRECT(
+ fosphor_block_control, FOSPHOR_BLOCK, "Fosphor", CLOCK_KEY_GRAPH, "bus_clk")