summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-uhd/CMakeLists.txt9
-rw-r--r--gr-uhd/examples/grc/rfnoc_radio_ddc.grc264
-rw-r--r--gr-uhd/grc/CMakeLists.txt27
-rw-r--r--gr-uhd/grc/rfnoc.domain.yml10
-rw-r--r--gr-uhd/grc/uhd.tree.yml23
-rw-r--r--gr-uhd/grc/uhd_fpga_clk.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_ctrl.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_data.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_ddc.block.yml38
-rw-r--r--gr-uhd/grc/uhd_fpga_duc.block.yml37
-rw-r--r--gr-uhd/grc/uhd_fpga_fft.block.yml12
-rw-r--r--gr-uhd/grc/uhd_fpga_io_ctrl_port.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_io_radio.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_io_time_keeper.domain.yml9
-rw-r--r--gr-uhd/grc/uhd_fpga_radio.block.yml47
-rw-r--r--gr-uhd/grc/uhd_fpga_sep.block.yml45
-rw-r--r--gr-uhd/grc/uhd_fpga_x310.block.yml38
-rw-r--r--gr-uhd/grc/uhd_rfnoc_ddc.block.yml57
-rw-r--r--gr-uhd/grc/uhd_rfnoc_duc.block.yml56
-rw-r--r--gr-uhd/grc/uhd_rfnoc_fft.block.yml45
-rw-r--r--gr-uhd/grc/uhd_rfnoc_graph.block.yml127
-rw-r--r--gr-uhd/grc/uhd_rfnoc_rx_radio.block.yml91
-rw-r--r--gr-uhd/grc/uhd_rfnoc_rx_streamer.block.yml57
-rw-r--r--gr-uhd/grc/uhd_rfnoc_tx_radio.block.yml77
-rw-r--r--gr-uhd/grc/uhd_rfnoc_tx_streamer.block.yml53
-rw-r--r--gr-uhd/include/gnuradio/uhd/CMakeLists.txt18
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_block.h89
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_block_generic.h50
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_ddc.h62
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_duc.h59
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_graph.h135
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_rx_radio.h168
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_rx_streamer.h62
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_tx_radio.h146
-rw-r--r--gr-uhd/include/gnuradio/uhd/rfnoc_tx_streamer.h59
-rw-r--r--gr-uhd/lib/CMakeLists.txt24
-rw-r--r--gr-uhd/lib/rfnoc_block.cc62
-rw-r--r--gr-uhd/lib/rfnoc_block_generic_impl.cc43
-rw-r--r--gr-uhd/lib/rfnoc_block_generic_impl.h27
-rw-r--r--gr-uhd/lib/rfnoc_ddc_impl.cc52
-rw-r--r--gr-uhd/lib/rfnoc_ddc_impl.h37
-rw-r--r--gr-uhd/lib/rfnoc_duc_impl.cc52
-rw-r--r--gr-uhd/lib/rfnoc_duc_impl.h37
-rw-r--r--gr-uhd/lib/rfnoc_graph_impl.cc214
-rw-r--r--gr-uhd/lib/rfnoc_rx_radio_impl.cc133
-rw-r--r--gr-uhd/lib/rfnoc_rx_radio_impl.h51
-rw-r--r--gr-uhd/lib/rfnoc_rx_streamer_impl.cc192
-rw-r--r--gr-uhd/lib/rfnoc_rx_streamer_impl.h73
-rw-r--r--gr-uhd/lib/rfnoc_tx_radio_impl.cc119
-rw-r--r--gr-uhd/lib/rfnoc_tx_radio_impl.h48
-rw-r--r--gr-uhd/lib/rfnoc_tx_streamer_impl.cc93
-rw-r--r--gr-uhd/lib/rfnoc_tx_streamer_impl.h59
-rw-r--r--gr-uhd/swig/CMakeLists.txt3
-rw-r--r--gr-uhd/swig/uhd_swig.i53
54 files changed, 3376 insertions, 11 deletions
diff --git a/gr-uhd/CMakeLists.txt b/gr-uhd/CMakeLists.txt
index e05f01ebf1..d79e309376 100644
--- a/gr-uhd/CMakeLists.txt
+++ b/gr-uhd/CMakeLists.txt
@@ -11,6 +11,11 @@
include(GrBoost)
find_package(UHD "3.9.7")
+if ("${UHD_VERSION}" VERSION_GREATER_EQUAL "4")
+ set(ENABLE_UHD_RFNOC TRUE)
+else()
+ set(ENABLE_UHD_RFNOC FALSE)
+endif()
########################################################################
# Register component
@@ -24,14 +29,14 @@ GR_REGISTER_COMPONENT("gr-uhd" ENABLE_GR_UHD
ENABLE_GR_BLOCKS
ENABLE_GR_ANALOG
)
-message(STATUS " UHD Version: ${UHD_VERSION}")
-
SET(GR_PKG_UHD_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/uhd)
########################################################################
# Begin conditional configuration
########################################################################
if(ENABLE_GR_UHD)
+message(STATUS " UHD Version: ${UHD_VERSION}")
+message(STATUS " UHD 4.0 RFNoC enabled: ${ENABLE_UHD_RFNOC}")
########################################################################
# Add subdirectories
diff --git a/gr-uhd/examples/grc/rfnoc_radio_ddc.grc b/gr-uhd/examples/grc/rfnoc_radio_ddc.grc
new file mode 100644
index 0000000000..6c473b487f
--- /dev/null
+++ b/gr-uhd/examples/grc/rfnoc_radio_ddc.grc
@@ -0,0 +1,264 @@
+options:
+ parameters:
+ author: Martin Braun <martin.braun@ettus.com>
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: rfnoc_radio_ddc
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: 'RFNoC: Radio -> DDC Example'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: freq
+ id: variable_qtgui_entry
+ parameters:
+ comment: ''
+ gui_hint: ''
+ label: Frequency (Hz)
+ type: real
+ value: 1e9
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [304, 71]
+ rotation: 0
+ state: true
+- name: gain
+ id: variable_qtgui_entry
+ parameters:
+ comment: ''
+ gui_hint: ''
+ label: Gain (dB)
+ type: int
+ value: '0'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [193, 71]
+ rotation: 0
+ state: true
+- name: samp_rate
+ id: variable_qtgui_entry
+ parameters:
+ comment: ''
+ gui_hint: ''
+ label: Sampling Rate (Hz)
+ type: real
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [441, 72]
+ rotation: 0
+ state: true
+- name: uhd_rfnoc_graph
+ id: uhd_rfnoc_graph
+ parameters:
+ alias: ''
+ clock_source_0: ''
+ clock_source_1: ''
+ clock_source_2: ''
+ clock_source_3: ''
+ clock_source_4: ''
+ clock_source_5: ''
+ clock_source_6: ''
+ clock_source_7: ''
+ comment: ''
+ dev_addr: type=x300
+ dev_args: ''
+ num_mboards: '1'
+ time_source_0: ''
+ time_source_1: ''
+ time_source_2: ''
+ time_source_3: ''
+ time_source_4: ''
+ time_source_5: ''
+ time_source_6: ''
+ time_source_7: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [193, 10]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''''''
+ label2: ''''''
+ label3: ''''''
+ label4: ''''''
+ label5: ''''''
+ label6: ''''''
+ label7: ''''''
+ label8: ''''''
+ label9: ''''''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'False'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '10'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [852, 244]
+ rotation: 0
+ state: true
+- name: uhd_rfnoc_ddc_0
+ id: uhd_rfnoc_ddc
+ parameters:
+ affinity: ''
+ alias: ''
+ block_args: ''
+ comment: ''
+ device_select: '-1'
+ freq: '0'
+ instance_index: '-1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_chans: '1'
+ output_rate: samp_rate
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [321, 200]
+ rotation: 0
+ state: true
+- name: uhd_rfnoc_rx_radio_0
+ id: uhd_rfnoc_rx_radio
+ parameters:
+ affinity: ''
+ agc: Default
+ alias: ''
+ antenna: RX2
+ bandwidth: '0'
+ block_args: ''
+ comment: ''
+ dc_offset: 'False'
+ device_select: '-1'
+ frequency: freq
+ gain: gain
+ instance_index: '-1'
+ iq_balance: 'False'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_chans: '1'
+ rate: 200e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [18, 152]
+ rotation: 0
+ state: true
+- name: uhd_rfnoc_rx_streamer_0
+ id: uhd_rfnoc_rx_streamer
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_chans: '1'
+ otw: sc16
+ output_type: fc32
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [633, 244]
+ rotation: 0
+ state: true
+
+connections:
+- [uhd_rfnoc_ddc_0, '0', uhd_rfnoc_rx_streamer_0, '0']
+- [uhd_rfnoc_rx_radio_0, '0', uhd_rfnoc_ddc_0, '0']
+- [uhd_rfnoc_rx_streamer_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-uhd/grc/CMakeLists.txt b/gr-uhd/grc/CMakeLists.txt
index 500859f880..044b716a7e 100644
--- a/gr-uhd/grc/CMakeLists.txt
+++ b/gr-uhd/grc/CMakeLists.txt
@@ -31,3 +31,30 @@ install(FILES
uhd.tree.yml
DESTINATION ${GRC_BLOCKS_DIR}
)
+
+if(ENABLE_UHD_RFNOC)
+ install(FILES
+ rfnoc.domain.yml
+ uhd_fpga_clk.domain.yml
+ uhd_fpga_ctrl.domain.yml
+ uhd_fpga_data.domain.yml
+ uhd_fpga_ddc.block.yml
+ uhd_fpga_duc.block.yml
+ uhd_fpga_fft.block.yml
+ uhd_fpga_io_ctrl_port.domain.yml
+ uhd_fpga_io_radio.domain.yml
+ uhd_fpga_io_time_keeper.domain.yml
+ uhd_fpga_radio.block.yml
+ uhd_fpga_sep.block.yml
+ uhd_fpga_x310.block.yml
+ uhd_rfnoc_ddc.block.yml
+ uhd_rfnoc_duc.block.yml
+ uhd_rfnoc_fft.block.yml
+ uhd_rfnoc_graph.block.yml
+ uhd_rfnoc_rx_radio.block.yml
+ uhd_rfnoc_rx_streamer.block.yml
+ uhd_rfnoc_tx_radio.block.yml
+ uhd_rfnoc_tx_streamer.block.yml
+ DESTINATION ${GRC_BLOCKS_DIR}
+ )
+endif(ENABLE_UHD_RFNOC)
diff --git a/gr-uhd/grc/rfnoc.domain.yml b/gr-uhd/grc/rfnoc.domain.yml
new file mode 100644
index 0000000000..5760864993
--- /dev/null
+++ b/gr-uhd/grc/rfnoc.domain.yml
@@ -0,0 +1,10 @@
+id: rfnoc
+label: RFNoC
+color: "#81b35d"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: false
+
+templates:
+- type: [rfnoc, rfnoc]
+ connect: self.rfnoc_graph.connect(self.${ source.parent_block.name }.get_unique_id(), ${ source.key }, self.${ sink.parent_block.name }.get_unique_id(), ${ sink.key }, False)
diff --git a/gr-uhd/grc/uhd.tree.yml b/gr-uhd/grc/uhd.tree.yml
index a4d140d779..e5c0c61871 100644
--- a/gr-uhd/grc/uhd.tree.yml
+++ b/gr-uhd/grc/uhd.tree.yml
@@ -3,3 +3,26 @@
- uhd_usrp_source
- uhd_usrp_sink
- uhd_amsg_source
+ - RFNoC:
+ - Device Control:
+ - uhd_rfnoc_graph
+ - Blocks:
+ - uhd_rfnoc_ddc
+ - uhd_rfnoc_duc
+ - uhd_rfnoc_fft
+ - uhd_rfnoc_rx_radio
+ - uhd_rfnoc_tx_radio
+ - uhd_rfnoc_rx_streamer
+ - uhd_rfnoc_tx_streamer
+ - RFNoC Image Builder:
+ - Blocks:
+ - uhd_fpga_ddc
+ - uhd_fpga_duc
+ - uhd_fpga_fft
+ - uhd_fpga_null_src_sink
+ - Core:
+ - uhd_fpga_sep
+ - uhd_fpga_radio
+ - uhd_fpga_x310
+ - uhd_fpga_ctrl_xbar
+ - uhd_fpga_chdr_xbar
diff --git a/gr-uhd/grc/uhd_fpga_clk.domain.yml b/gr-uhd/grc/uhd_fpga_clk.domain.yml
new file mode 100644
index 0000000000..e459ed2d06
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_clk.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.clk
+label: Clock
+color: "#72706F"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.clk, rfnoc.clk]
diff --git a/gr-uhd/grc/uhd_fpga_ctrl.domain.yml b/gr-uhd/grc/uhd_fpga_ctrl.domain.yml
new file mode 100644
index 0000000000..64f2b76846
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_ctrl.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.ctrl
+label: Control
+color: "#F50057"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.ctrl, rfnoc.ctrl]
diff --git a/gr-uhd/grc/uhd_fpga_data.domain.yml b/gr-uhd/grc/uhd_fpga_data.domain.yml
new file mode 100644
index 0000000000..35ff4fd90d
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_data.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.data
+label: Data
+color: "#2196F3"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.data, rfnoc.data]
diff --git a/gr-uhd/grc/uhd_fpga_ddc.block.yml b/gr-uhd/grc/uhd_fpga_ddc.block.yml
new file mode 100644
index 0000000000..f06d6bd296
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_ddc.block.yml
@@ -0,0 +1,38 @@
+id: uhd_fpga_ddc
+label: DDC
+
+parameters:
+- id: type
+ label: RFNoC Block Type
+ dtype: enum
+ default: 'block'
+ options: ['block', 'sep', 'device']
+ hide: all
+- id: desc
+ label: Block Descriptor
+ dtype: string
+ default: 'ddc_2x64.yml'
+ hide: all
+- id: nports
+ label: Number of Ports
+ dtype: int
+ default: '1'
+ hide: part
+
+
+inputs:
+- domain: rfnoc.clk
+ id: ddc
+ dtype: message
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+outputs:
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_fpga_duc.block.yml b/gr-uhd/grc/uhd_fpga_duc.block.yml
new file mode 100644
index 0000000000..eabd984396
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_duc.block.yml
@@ -0,0 +1,37 @@
+id: uhd_fpga_duc
+label: DUC
+
+parameters:
+- id: type
+ label: RFNoC Block Type
+ dtype: enum
+ default: 'block'
+ options: ['block', 'sep', 'device']
+ hide: all
+- id: desc
+ label: Block Descriptor
+ dtype: string
+ default: 'duc_2x64.yml'
+ hide: all
+- id: nports
+ label: Number of Ports
+ dtype: int
+ default: '2'
+ hide: part
+
+inputs:
+- domain: rfnoc.clk
+ id: duc
+ dtype: message
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+outputs:
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_fpga_fft.block.yml b/gr-uhd/grc/uhd_fpga_fft.block.yml
new file mode 100644
index 0000000000..231a3dbf64
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_fft.block.yml
@@ -0,0 +1,12 @@
+id: uhd_fpga_fft
+label: FFT
+
+inputs:
+- domain: stream
+ id: port0
+
+outputs:
+- domain: stream
+ id: port0
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_fpga_io_ctrl_port.domain.yml b/gr-uhd/grc/uhd_fpga_io_ctrl_port.domain.yml
new file mode 100644
index 0000000000..b0613c5f35
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_io_ctrl_port.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.io.ctrl_port
+label: Control Port
+color: "#00BCD4"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.io.ctrl_port, rfnoc.io.ctrl_port]
diff --git a/gr-uhd/grc/uhd_fpga_io_radio.domain.yml b/gr-uhd/grc/uhd_fpga_io_radio.domain.yml
new file mode 100644
index 0000000000..a186c9ad51
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_io_radio.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.io.radio
+label: Radio
+color: "#4CAF50"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.io.radio, rfnoc.io.radio]
diff --git a/gr-uhd/grc/uhd_fpga_io_time_keeper.domain.yml b/gr-uhd/grc/uhd_fpga_io_time_keeper.domain.yml
new file mode 100644
index 0000000000..0f983b6320
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_io_time_keeper.domain.yml
@@ -0,0 +1,9 @@
+id: rfnoc.io.time_keeper
+label: Time Keeper
+color: "#F57C00"
+
+multiple_connections_per_input: false
+multiple_connections_per_output: true
+
+templates:
+- type: [rfnoc.io.time_keeper, rfnoc.io.time_keeper]
diff --git a/gr-uhd/grc/uhd_fpga_radio.block.yml b/gr-uhd/grc/uhd_fpga_radio.block.yml
new file mode 100644
index 0000000000..a2ea1035f5
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_radio.block.yml
@@ -0,0 +1,47 @@
+id: uhd_fpga_radio
+label: Radio
+
+parameters:
+- id: type
+ label: RFNoC Block Type
+ dtype: enum
+ default: 'block'
+ options: ['block', 'sep', 'device']
+ hide: all
+- id: desc
+ label: Block Descriptor
+ dtype: string
+ default: 'radio_2x64.yml'
+ hide: all
+- id: nports
+ label: Number of Ports
+ dtype: int
+ default: '2'
+ hide: part
+
+inputs:
+- domain: rfnoc.clk
+ id: radio
+ dtype: message
+- domain: rfnoc.io.time_keeper
+ id: time_keeper
+ dtype: f32
+- domain: rfnoc.io.radio
+ id: x300_radio
+ dtype: sc32
+
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+outputs:
+- domain: rfnoc.io.ctrl_port
+ id: ctrl_port
+ dtype: f64
+- domain: rfnoc.data
+ id: port
+ dtype: fc32
+ multiplicity: ${ nports }
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_fpga_sep.block.yml b/gr-uhd/grc/uhd_fpga_sep.block.yml
new file mode 100644
index 0000000000..7e0100c9be
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_sep.block.yml
@@ -0,0 +1,45 @@
+id: uhd_fpga_sep
+label: Stream Endpoint
+flags: [ python ]
+
+parameters:
+- id: type
+ label: RFNoC Block Type
+ dtype: enum
+ default: 'sep'
+ options: ['block', 'sep', 'device']
+ hide: all
+- id: ctrl
+ label: Pass Control Traffic
+ dtype: enum
+ default: 'True'
+ options: ['True', 'False']
+ option_labels: ['Yes', 'No']
+ hide: part
+- id: data
+ label: Pass Data Traffic
+ dtype: enum
+ default: 'True'
+ options: ['True', 'False']
+ option_labels: ['Yes', 'No']
+ hide: part
+- id: buff_size
+ label: Buffer Size
+ dtype: int
+ default: '32768'
+ hide: part
+
+
+inputs:
+- domain: rfnoc.data
+ id: in0
+ dtype: fc32
+ multiplicity: ${ nports }
+
+outputs:
+- domain: rfnoc.data
+ id: out0
+ dtype: fc32
+ multiplicity: ${ nports }
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_fpga_x310.block.yml b/gr-uhd/grc/uhd_fpga_x310.block.yml
new file mode 100644
index 0000000000..26b07fae80
--- /dev/null
+++ b/gr-uhd/grc/uhd_fpga_x310.block.yml
@@ -0,0 +1,38 @@
+id: uhd_fpga_x310
+label: X310 Device
+
+parameters:
+- id: type
+ label: RFNoC Block Type
+ dtype: enum
+ default: 'device'
+ options: ['block', 'sep', 'device']
+ hide: all
+
+inputs:
+- domain: rfnoc.io.ctrl_port
+ id: ctrlport_radio0
+ dtype: f64
+- domain: rfnoc.io.ctrl_port
+ id: ctrlport_radio1
+ dtype: f64
+
+outputs:
+- domain: rfnoc.clk
+ id: radio
+ dtype: message
+- domain: rfnoc.clk
+ id: ce
+ dtype: message
+
+- domain: rfnoc.io.time_keeper
+ id: time_keeper
+ dtype: f32
+- domain: rfnoc.io.radio
+ id: x300_radio0
+ dtype: sc32
+- domain: rfnoc.io.radio
+ id: x300_radio1
+ dtype: sc32
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_ddc.block.yml b/gr-uhd/grc/uhd_rfnoc_ddc.block.yml
new file mode 100644
index 0000000000..86925f476b
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_ddc.block.yml
@@ -0,0 +1,57 @@
+id: uhd_rfnoc_ddc
+label: RFNoC Digital Downconverter Block
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_ddc(
+ self.rfnoc_graph,
+ uhd.device_addr(${block_args}),
+ ${device_select},
+ ${instance_index})
+ self.${id}.set_freq(${freq}, 0)
+ self.${id}.set_output_rate(${output_rate}, 0)
+ callbacks:
+ - set_freq(${freq}, 0)
+ - set_output_rate(${output_rate}, 0)
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+- id: block_args
+ label: Block Args
+ dtype: string
+ default: ""
+- id: device_select
+ label: Device Select
+ dtype: int
+ default: -1
+- id: instance_index
+ label: Instance Select
+ dtype: int
+ default: -1
+- id: freq
+ label: Frequency Shift (Hz)
+ dtype: real
+ default: 0
+- id: output_rate
+ label: Output Rate (Hz)
+ dtype: real
+ default: 0
+
+inputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+outputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_duc.block.yml b/gr-uhd/grc/uhd_rfnoc_duc.block.yml
new file mode 100644
index 0000000000..6adc89cc78
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_duc.block.yml
@@ -0,0 +1,56 @@
+id: uhd_rfnoc_duc
+label: RFNoC Digital Upconverter Block
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_duc(
+ self.rfnoc_graph,
+ ${num_chans},
+ uhd.device_addr(${block_args}),
+ ${device_select},
+ ${instance_index})
+ self.${id}.set_freq(${freq}, 0)
+ self.${id}.set_input_rate(${input_rate}, 0)
+ callbacks:
+ - set_freq(${freq}, 0)
+ - set_input_rate(${input_rate}, 0)
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+- id: block_args
+ label: Block Args
+ dtype: string
+ default: ""
+- id: device_select
+ label: Device Select
+ dtype: int
+ default: -1
+- id: instance_index
+ label: Instance Select
+ dtype: int
+ default: -1
+- id: freq
+ label: Frequency Shift (Hz)
+ dtype: real
+- id: input_rate
+ label: Input Rate (Hz)
+ dtype: real
+
+inputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+outputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_fft.block.yml b/gr-uhd/grc/uhd_rfnoc_fft.block.yml
new file mode 100644
index 0000000000..28f88f20e3
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_fft.block.yml
@@ -0,0 +1,45 @@
+id: uhd_rfnoc_fft
+label: RFNoC Fast Fourier Transform Block
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_block_generic(
+ self.rfnoc_graph,
+ uhd.device_addr(${block_args}),
+ "FFT",
+ ${device_select},
+ ${instance_index})
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+- id: block_args
+ label: Block Args
+ dtype: string
+ default: ""
+- id: device_select
+ label: Device Select
+ dtype: int
+ default: -1
+- id: instance_index
+ label: Instance Select
+ dtype: int
+ default: -1
+
+inputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+outputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_graph.block.yml b/gr-uhd/grc/uhd_rfnoc_graph.block.yml
new file mode 100644
index 0000000000..43b1bce491
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_graph.block.yml
@@ -0,0 +1,127 @@
+id: uhd_rfnoc_graph
+label: RFNoC Graph (Device)
+flags: [ show_id, python ]
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ var_make: |
+ self.rfnoc_graph = ${id} = uhd.rfnoc_graph(uhd.device_addr(",".join((${dev_addr}, ${dev_args}))))
+
+value: ${ 'RFNoC Graph' }
+
+parameters:
+- id: dev_addr
+ label: Device Address
+ dtype: string
+ default: ""
+ hide: ${ 'none' if dev_addr else 'part' }
+- id: dev_args
+ label: Device Args
+ dtype: string
+ default: ""
+ hide: ${ 'none' if dev_args else 'part' }
+- id: num_mboards
+ label: Num Mboards
+ dtype: int
+ default: 1
+ options: [1, 2, 3, 4, 5, 6, 7, 8]
+ hide: part
+- id: clock_source_0
+ label: 'Mb0: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 0) else ( 'none' if clock_source_0 else 'part')}
+- id: time_source_0
+ label: 'Mb0: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 0) else ('none' if time_source_0 else 'part')}
+- id: clock_source_1
+ label: 'Mb1: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 1) else ( 'none' if clock_source_1 else 'part')}
+- id: time_source_1
+ label: 'Mb1: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 1) else ('none' if time_source_1 else 'part')}
+- id: clock_source_2
+ label: 'Mb2: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 2) else ( 'none' if clock_source_2 else 'part')}
+- id: time_source_2
+ label: 'Mb2: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 2) else ('none' if time_source_2 else 'part')}
+- id: clock_source_3
+ label: 'Mb3: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 3) else ( 'none' if clock_source_3 else 'part')}
+- id: time_source_3
+ label: 'Mb3: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 3) else ('none' if time_source_3 else 'part')}
+- id: clock_source_4
+ label: 'Mb4: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 4) else ( 'none' if clock_source_4 else 'part')}
+- id: time_source_4
+ label: 'Mb4: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 4) else ('none' if time_source_4 else 'part')}
+- id: clock_source_5
+ label: 'Mb5: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 5) else ( 'none' if clock_source_5 else 'part')}
+- id: time_source_5
+ label: 'Mb5: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 5) else ('none' if time_source_5 else 'part')}
+- id: clock_source_6
+ label: 'Mb6: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 6) else ( 'none' if clock_source_6 else 'part')}
+- id: time_source_6
+ label: 'Mb6: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 6) else ('none' if time_source_6 else 'part')}
+- id: clock_source_7
+ label: 'Mb7: Clock Source'
+ dtype: string
+ options: ['', internal, external, mimo, gpsdo]
+ option_labels: [Default, Internal, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 7) else ( 'none' if clock_source_7 else 'part')}
+- id: time_source_7
+ label: 'Mb7: Time Source'
+ dtype: string
+ options: ['', external, mimo, gpsdo]
+ option_labels: [Default, External, MIMO Cable, O/B GPSDO]
+ hide: ${ 'all' if not (num_mboards > 7) else ('none' if time_source_7 else 'part')}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_rx_radio.block.yml b/gr-uhd/grc/uhd_rfnoc_rx_radio.block.yml
new file mode 100644
index 0000000000..653249befa
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_rx_radio.block.yml
@@ -0,0 +1,91 @@
+id: uhd_rfnoc_rx_radio
+label: RFNoC RX Radio
+flags: [python, throttle]
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_rx_radio(
+ self.rfnoc_graph,
+ uhd.device_addr(${block_args}),
+ ${device_select},
+ ${instance_index})
+ self.${id}.set_rate(${rate})
+ self.${id}.set_antenna(${antenna}, 0)
+ self.${id}.set_frequency(${frequency}, 0)
+ self.${id}.set_gain(${gain}, 0)
+ self.${id}.set_bandwidth(${bandwidth}, 0)
+ self.${id}.set_dc_offset(${dc_offset}, 0)
+ self.${id}.set_iq_balance(${iq_balance}, 0)
+ callbacks:
+ - set_rate(${rate})
+ - set_antenna(${antenna}, 0)
+ - set_frequency(${frequency}, 0)
+ - set_gain(${gain}, 0)
+ - set_bandwidth(${bandwidth}, 0)
+ - set_dc_offset(${dc_offset}, 0)
+ - set_iq_balance(${iq_balance}, 0)
+
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+- id: block_args
+ label: Block Args
+ dtype: string
+ default: ""
+- id: device_select
+ label: Device Select
+ dtype: int
+ default: -1
+- id: instance_index
+ label: Instance Select
+ dtype: int
+ default: -1
+- id: rate
+ label: Sample Rate (Hz)
+ dtype: real
+- id: antenna
+ label: Antenna Select
+ dtype: string
+ options: [TX/RX, RX2, RX1]
+ option_labels: [TX/RX, RX2, RX1]
+ default: RX2
+- id: frequency
+ label: Center Frequency (Hz)
+ dtype: real
+- id: gain
+ label: Gain
+ dtype: real
+- id: agc
+ label: Automatic Gain Control
+ dtype: string
+ default: 'Default'
+ options: ['Default', 'Disabled', 'Enabled']
+ option_labels: [Default, Disabled, Enabled]
+- id: bandwidth
+ label: Bandwidth (Hz)
+ dtype: real
+ default: 0
+- id: dc_offset
+ label: DC Offset Correction
+ dtype: bool
+ options: ['True', 'False']
+ default: 'False'
+- id: iq_balance
+ label: IQ Balance
+ dtype: bool
+ options: ['True', 'False']
+ default: 'False'
+
+
+outputs:
+- domain: rfnoc
+ dtype: sc16
+ vlen: 1
+ multiplicity: ${num_chans}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_rx_streamer.block.yml b/gr-uhd/grc/uhd_rfnoc_rx_streamer.block.yml
new file mode 100644
index 0000000000..e0489eff85
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_rx_streamer.block.yml
@@ -0,0 +1,57 @@
+id: uhd_rfnoc_rx_streamer
+label: RFNoC Rx Streamer
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_rx_streamer(
+ self.rfnoc_graph,
+ ${ num_chans },
+ uhd.stream_args(
+ cpu_format="${ output_type.type }",
+ otw_format="${ otw.type }",
+ channels=[],
+ args="",
+ ),
+ 1,
+ True
+ )
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+ hide: part
+- id: otw
+ label: Wire Format
+ dtype: enum
+ options: ['', sc16]
+ option_labels: [Automatic, Complex int16]
+ option_attributes:
+ type: ['', sc16]
+ hide: part
+- id: output_type
+ label: Output Type
+ dtype: enum
+ options: [fc32, sc16]
+ option_labels: [Complex float32, Complex int16]
+ option_attributes:
+ type: [fc32, sc16]
+ hide: part
+
+asserts:
+ - ${ num_chans > 0 }
+
+inputs:
+- domain: rfnoc
+ dtype: ${ otw.type }
+ multiplicity: ${ num_chans }
+
+outputs:
+- domain: stream
+ dtype: ${ output_type.type }
+ multiplicity: ${ num_chans }
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_tx_radio.block.yml b/gr-uhd/grc/uhd_rfnoc_tx_radio.block.yml
new file mode 100644
index 0000000000..93392cb7f3
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_tx_radio.block.yml
@@ -0,0 +1,77 @@
+id: uhd_rfnoc_tx_radio
+label: RFNoC TX Radio
+flags: [python, throttle]
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_tx_radio(
+ self.rfnoc_graph,
+ uhd.device_addr(${block_args}),
+ ${device_select},
+ ${instance_index})
+ self.${id}.set_rate(${rate})
+ self.${id}.set_antenna(${antenna}, 0)
+ self.${id}.set_frequency(${frequency}, 0)
+ self.${id}.set_gain(${gain}, 0)
+ self.${id}.set_bandwidth(${bandwidth}, 0)
+ callbacks:
+ - set_rate(${rate})
+ - set_antenna(${antenna}, 0)
+ - set_frequency(${frequency}, 0)
+ - set_gain(${gain}, 0)
+ - set_bandwidth(${bandwidth}, 0)
+
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+- id: block_args
+ label: Block Args
+ dtype: string
+ default: ""
+- id: device_select
+ label: Device Select
+ dtype: int
+ default: -1
+- id: instance_index
+ label: Instance Select
+ dtype: int
+ default: -1
+- id: rate
+ label: Sample Rate (Hz)
+ dtype: real
+- id: antenna
+ label: Antenna Select
+ dtype: string
+ options: [TX/RX, RX2, RX1]
+ option_labels: [TX/RX, RX2, RX1]
+ default: TX/RX
+- id: frequency
+ label: Center Frequency (Hz)
+ dtype: real
+- id: gain
+ label: Gain
+ dtype: real
+- id: agc
+ label: Automatic Gain Control
+ dtype: string
+ default: 'Default'
+ options: ['Default', 'Enabled', 'Disabled']
+ option_labels: [Default, Disabled, Enabled]
+- id: bandwidth
+ label: Bandwidth (Hz)
+ dtype: real
+ default: 0
+
+
+inputs:
+- domain: rfnoc
+ dtype: 'sc16'
+ vlen: 1
+ multiplicity: ${num_chans}
+
+file_format: 1
diff --git a/gr-uhd/grc/uhd_rfnoc_tx_streamer.block.yml b/gr-uhd/grc/uhd_rfnoc_tx_streamer.block.yml
new file mode 100644
index 0000000000..881ae21df0
--- /dev/null
+++ b/gr-uhd/grc/uhd_rfnoc_tx_streamer.block.yml
@@ -0,0 +1,53 @@
+id: uhd_rfnoc_tx_streamer
+label: RFNoC Tx Streamer
+
+templates:
+ imports: |-
+ from gnuradio import uhd
+ make: |-
+ uhd.rfnoc_tx_streamer(
+ self.rfnoc_graph,
+ ${ num_chans },
+ uhd.stream_args(
+ cpu_format="${ input_type.type }",
+ otw_format="${ otw.type }",
+ channels=[],
+ args="",
+ ),
+ 1
+ )
+
+parameters:
+- id: num_chans
+ label: Number of Channels
+ dtype: int
+ default: 1
+ hide: part
+- id: input_type
+ label: Input Type
+ dtype: enum
+ options: [fc32, sc16]
+ option_labels: [Complex float32, Complex int16]
+ option_attributes:
+ type: [fc32, sc16]
+ hide: part
+- id: otw
+ label: Wire Format
+ dtype: enum
+ options: ['', sc16]
+ option_labels: [Automatic, Complex int16]
+ option_attributes:
+ type: ['', sc16]
+ hide: part
+
+inputs:
+- domain: stream
+ dtype: ${ input_type.type }
+ multiplicity: ${ num_chans }
+
+outputs:
+- domain: rfnoc
+ dtype: ${ otw.type }
+ multiplicity: ${ num_chans }
+
+file_format: 1
diff --git a/gr-uhd/include/gnuradio/uhd/CMakeLists.txt b/gr-uhd/include/gnuradio/uhd/CMakeLists.txt
index e75369b1ee..ffe1f6404d 100644
--- a/gr-uhd/include/gnuradio/uhd/CMakeLists.txt
+++ b/gr-uhd/include/gnuradio/uhd/CMakeLists.txt
@@ -9,10 +9,24 @@
# Install header files
########################################################################
install(FILES
+ amsg_source.h
api.h
usrp_block.h
- usrp_source.h
usrp_sink.h
- amsg_source.h
+ usrp_source.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/uhd
)
+
+if (ENABLE_UHD_RFNOC)
+ install(FILES
+ rfnoc_block_generic.h
+ rfnoc_ddc.h
+ rfnoc_duc.h
+ rfnoc_graph.h
+ rfnoc_rx_radio.h
+ rfnoc_rx_streamer.h
+ rfnoc_tx_radio.h
+ rfnoc_tx_streamer.h
+ DESTINATION ${GR_INCLUDE_DIR}/gnuradio/uhd
+ )
+endif (ENABLE_UHD_RFNOC)
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_block.h b/gr-uhd/include/gnuradio/uhd/rfnoc_block.h
new file mode 100644
index 0000000000..a25a502542
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_block.h
@@ -0,0 +1,89 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_UHD_RFNOC_BLOCK_H
+#define INCLUDED_UHD_RFNOC_BLOCK_H
+
+#include <gnuradio/block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+#include <uhd/rfnoc/noc_block_base.hpp>
+#include <string>
+
+namespace gr {
+namespace uhd {
+
+/*! Base class for RFNoC blocks controlled by GNU Radio
+ *
+ * Any GNU Radio block that is meant to control an RFNoC block
+ * should be derived from this class.
+ */
+class UHD_API rfnoc_block : public gr::block
+{
+protected:
+ // \param block_ref A reference to the underlying block controller
+ rfnoc_block(::uhd::rfnoc::noc_block_base::sptr block_ref);
+
+ rfnoc_block() {} // For virtual subclassing
+
+public:
+ using sptr = boost::shared_ptr<rfnoc_block>;
+
+ //! Factory function to create a UHD block controller reference
+ //
+ // \param graph Refernce to the flowgraph's RFNoC graph
+ // \param block_args Block args
+ // \param block_name Block name (e.g. "DDC")
+ // \param device_select Device index (motherboard index)
+ // \param block_select Block index
+ // \param max_ref_count Maximum number of references this block can have in
+ // the GNU Radio flow graph
+ static ::uhd::rfnoc::noc_block_base::sptr
+ make_block_ref(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const std::string& block_name,
+ const int device_select = -1,
+ const int block_select = -1,
+ const size_t max_ref_count = 1);
+
+ //! Return a type-cast block reference, or throw if the cast failed.
+ //
+ // \throws std::runtime_error if there is no valid block reference
+ template <typename block_type>
+ std::shared_ptr<block_type> get_block_ref()
+ {
+ auto cast_block_ref = std::dynamic_pointer_cast<block_type>(d_block_ref);
+ if (!cast_block_ref) {
+ throw std::runtime_error(
+ std::string(
+ "Unable to cast the following block into its desired type: ") +
+ d_block_ref->get_unique_id());
+ }
+ return cast_block_ref;
+ }
+
+ /*! Return the unique ID of the underlying block
+ */
+ std::string get_unique_id() const;
+
+ // GNU Radio-specific overrides
+
+ //! This method should never be called by RFNoC blocks, they do the work
+ // in the FPGA.
+ int general_work(int noutput_items,
+ gr_vector_int& ninput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items);
+
+private:
+ //! Reference to the underlying RFNoC block
+ ::uhd::rfnoc::noc_block_base::sptr d_block_ref;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_UHD_RFNOC_BLOCK_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_block_generic.h b/gr-uhd/include/gnuradio/uhd/rfnoc_block_generic.h
new file mode 100644
index 0000000000..9cf7f91de6
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_block_generic.h
@@ -0,0 +1,50 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_H
+#define INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_H
+
+#include <gnuradio/block.h>
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+
+namespace gr {
+namespace uhd {
+
+/*! Generic RFNoC block holder
+ *
+ * This block can represent any RFNoC block
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_block_generic : virtual public rfnoc_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_block_generic> sptr;
+
+ /*!
+ * \param graph Reference to the underlying rfnoc_graph object
+ * \param block_args Arguments that get passed into the block
+ * \param block_name Block name. This argument, along with \p device_select
+ * and \p block_select, are used to identify which block
+ * is instantiated.
+ * \param device_select Optional: Device count.
+ * \param block_select Optional: Block select.
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const std::string& block_name,
+ const int device_select = -1,
+ const int block_select = -1);
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_ddc.h b/gr-uhd/include/gnuradio/uhd/rfnoc_ddc.h
new file mode 100644
index 0000000000..9b3a0d4c13
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_ddc.h
@@ -0,0 +1,62 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_DDC_H
+#define INCLUDED_GR_UHD_RFNOC_DDC_H
+
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_block.h>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC Digital Downconverter Block
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_ddc : virtual public rfnoc_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_ddc> sptr;
+
+ /*!
+ * \param graph Reference to the rfnoc_graph object this block is attached to
+ * \param block_args Additional block arguments
+ * \param device_select Device Selection
+ * \param instance Instance Selection
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance);
+
+ /*! Set the DDS frequency of the DDC
+ *
+ * \param freq Frequency Shift (Hz)
+ * \param chan Channel Index
+ * \param time Command Time for the frequency shift
+ */
+ virtual double set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time = ::uhd::time_spec_t::ASAP) = 0;
+
+ /*! Manually configure output rate
+ *
+ * When the DDC block is connected to an RX streamer block, then this will
+ * help with the property propagation.
+ *
+ * \param rate Sampling Rate (Hz)
+ * \param chan Channel Index
+ */
+ virtual double set_output_rate(const double rate, const size_t chan) = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_DDC_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_duc.h b/gr-uhd/include/gnuradio/uhd/rfnoc_duc.h
new file mode 100644
index 0000000000..f6b1227066
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_duc.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_DUC_H
+#define INCLUDED_GR_UHD_RFNOC_DUC_H
+
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC Digital Upconverter Block
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_duc : virtual public rfnoc_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_duc> sptr;
+
+ /*!
+ * \param graph Reference to the rfnoc_graph object this block is attached to
+ * \param block_args Additional block arguments
+ * \param device_select Device Selection
+ * \param instance Instance Selection
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance);
+
+ /*! Set DDS frequency
+ */
+ virtual double set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time = ::uhd::time_spec_t::ASAP) = 0;
+
+ /*! Set the sample rate at the input
+ *
+ * When the DUC block is connected to a TX streamer block, then this will
+ * help with the property propagation.
+ *
+ * \param rate Input Sampling Rate (Hz)
+ * \param chan Channel Index
+ */
+ virtual double set_input_rate(const double rate, const size_t chan) = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_DUC_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_graph.h b/gr-uhd/include/gnuradio/uhd/rfnoc_graph.h
new file mode 100644
index 0000000000..efa0e14c30
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_graph.h
@@ -0,0 +1,135 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_GRAPH_H
+#define INCLUDED_GR_UHD_RFNOC_GRAPH_H
+
+#include <gnuradio/uhd/api.h>
+#include <uhd/rfnoc/noc_block_base.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_block;
+
+/*! GNU Radio-specific wrapper for uhd::rfnoc::rfnoc_graph
+ *
+ * This wraps uhd::rfnoc::rfnoc_graph for simpler insertion into GNU Radio flow
+ * graphs. All API calls match those on said class.
+ */
+class GR_UHD_API rfnoc_graph
+{
+public:
+ using sptr = boost::shared_ptr<rfnoc_graph>;
+
+ static sptr make(const ::uhd::device_addr_t& dev_addr);
+
+ virtual ~rfnoc_graph() {}
+
+ //! Connect two blocks, or a block to a streamer, or a streamer to a block
+ //
+ // \param src_block The block ID of the source block (e.g., "0/Radio#0)
+ // \param src_block_port The port on the source block to connect to
+ // \param dst_block The block ID of the destination block (e.g., "0/DDC#0)
+ // \param dst_block_port The port on the destination block to connect to
+ // \param skip_property_propagation Disable property propagation on this
+ // connection (see the UHD documentation)
+ virtual void connect(const std::string& src_block,
+ const size_t src_block_port,
+ const std::string& dst_block,
+ const size_t dst_block_port,
+ const bool skip_property_propagation = false) = 0;
+
+ //! Convenience overload: Defaults to port 0 on both blocks
+ //
+ // \param src_block The block ID of the source block (e.g., "0/Radio#0)
+ // \param dst_block The block ID of the destination block (e.g., "0/DDC#0)
+ // \param skip_property_propagation Disable property propagation on this
+ // connection (see the UHD documentation)
+ virtual void connect(const std::string& src_block,
+ const std::string& dst_block,
+ const bool skip_property_propagation = false) = 0;
+
+ //! Create an RX streamer
+ //
+ // Note: This streamer is not connected to anything after creation.
+ //
+ // See also the UHD documentation for uhd::rfnoc::rfnoc_graph::create_rx_streamer().
+ //
+ // \param num_ports Number of streaming ports
+ // \param args Stream args.
+ virtual ::uhd::rx_streamer::sptr
+ create_rx_streamer(const size_t num_ports, const ::uhd::stream_args_t& args) = 0;
+
+ //! Create a TX streamer
+ //
+ // Note: This streamer is not connected to anything after creation.
+ //
+ // See also the UHD documentation for uhd::rfnoc::rfnoc_graph::create_tx_streamer().
+ //
+ // \param num_ports Number of streaming ports
+ // \param args Stream args.
+ virtual ::uhd::tx_streamer::sptr
+ create_tx_streamer(const size_t num_ports, const ::uhd::stream_args_t& args) = 0;
+
+ //! Commit the graph and run initial checks
+ //
+ // See ::uhd::rfnoc::rfnoc_graph::commit() for more documentation.
+ virtual void commit() = 0;
+
+ /*! Return a valid block ID string, if it exists, or an empty string, if not
+ *
+ * This will check the available blocks on the connected devices and see if
+ * they match the block name, device ID, and block number.
+ */
+ virtual std::string get_block_id(const std::string& block_name,
+ const int device_select,
+ const int block_select) = 0;
+
+ //! Set time source on the specified motherboard
+ //
+ // Note: This is a convenience call, it directly dereferences the underlying
+ // motherboard controller.
+ //
+ // \param source Time source (e.g., "internal")
+ // \param mb_index Motherboard index, starting at 0
+ virtual void set_time_source(const std::string& source, const size_t mb_index) = 0;
+
+ //! Set clock source on the specified motherboard
+ //
+ // Note: This is a convenience call, it directly dereferences the underlying
+ // motherboard controller.
+ //
+ // \param source Clock source (e.g., "internal")
+ // \param mb_index Motherboard index, starting at 0
+ virtual void set_clock_source(const std::string& source, const size_t mb_index) = 0;
+
+ //! Return a reference to the block with a given block ID
+ //
+ // This allows to retrieve a shared pointer to a block controller with a
+ // limit. It keeps track of the references given out, and will throw an
+ // exception if called more than max_ref_count times. This is to help ensure
+ // that GNU Radio blocks don't share block controllers unintentionally.
+ //
+ // \param block_id A valid block ID. Use get_block_id() to make sure it is
+ // valid.
+ // \param max_ref_count The maximum number of references that are doled out.
+ //
+ // \throws std::runtime_error if more than \p max_ref_count references are
+ // given out
+ virtual ::uhd::rfnoc::noc_block_base::sptr
+ get_block_ref(const std::string& block_id, const size_t max_ref_count) = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_GRAPH_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_rx_radio.h b/gr-uhd/include/gnuradio/uhd/rfnoc_rx_radio.h
new file mode 100644
index 0000000000..6a8e43ad1a
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_rx_radio.h
@@ -0,0 +1,168 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_RX_RADIO_H
+#define INCLUDED_GR_UHD_RFNOC_RX_RADIO_H
+
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC RX Radio
+ *
+ * This wraps a radio block into GNU Radio. Note: When doing TX and RX in the
+ * same flow graph, simply crate an rfnoc_rx_radio and an rfnoc_tx_radio with
+ * the same block ID.
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_rx_radio : virtual public rfnoc_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_rx_radio> sptr;
+
+ /*!
+ * \param graph Reference to the underlying rfnoc_graph object
+ * \param block_args Additional block arguments
+ * \param device_select Device Selection
+ * \param instance Instance Selection
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance);
+
+ //! Set the output sampling rate of the radio block
+ //
+ // Note: The actual rate of the radio will be coerced to whatever it is
+ // capable of.
+ //
+ // \param rate The new sampling rate
+ virtual double set_rate(const double rate) = 0;
+
+ //! Set the antenna for this radio
+ //
+ // \param antenna The antenna name (e.g., "RX2"). Valid name depend on the
+ // underlying hardware.
+ // \param chan The channel for which this antenna setting is for
+ virtual void set_antenna(const std::string& antenna, const size_t chan) = 0;
+
+ //! Set the RX frequency for this radio
+ //
+ // \param frequency The received frequency (e.g., 1e9)
+ // \param chan The channel for which this frequency setting is for
+ virtual double set_frequency(const double frequency, const size_t chan) = 0;
+
+ //! Configure the tune args for this RX radio
+ //
+ // \param args The new args (e.g., "mode_n=1")
+ // \param chan The channel for which this setting is for
+ virtual void set_tune_args(const ::uhd::device_addr_t& args, const size_t chan) = 0;
+
+ //! Configure the overall gain for this RX radio
+ //
+ // \param gain The new gain value (in dB)
+ // \param chan The channel for which this setting is for
+ virtual double set_gain(const double gain, const size_t chan) = 0;
+
+ //! Configure a specific gain for this RX radio
+ //
+ // \param gain The new gain value (in dB)
+ // \param name The gain stage name to set
+ // \param chan The channel for which this setting is for
+ virtual double
+ set_gain(const double gain, const std::string& name, const size_t chan) = 0;
+
+ //! Enable/disable the AGC for this RX radio (if available)
+ //
+ // \param enable The new setting for the AGC (on or off)
+ // \param chan The channel for which this setting is for
+ virtual void set_agc(const bool enable, const size_t chan) = 0;
+
+ //! Switch the gain profile for this RX radio
+ //
+ // \param profile The name of the gain profile (e.g., "low-noise")
+ // \param chan The channel for which this setting is for
+ virtual void set_gain_profile(const std::string& profile, const size_t chan) = 0;
+
+ //! Set the analog bandwidth for this RX radio
+ //
+ // \param bandwidth The new bandwidth, in Hz
+ // \param chan The channel for which this setting is for
+ virtual double set_bandwidth(const double bandwidth, const size_t chan) = 0;
+
+ //! Set the LO source for this RX radio
+ //
+ // Note: Available sources depend on the underlying hardware.
+ //
+ // \param source The new LO source (e.g., "internal")
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual void set_lo_source(const std::string& source,
+ const std::string& name,
+ const size_t chan) = 0;
+
+ //! Enable/disable LO export for this RX radio
+ //
+ // \param enabled When true, export this LO
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual void set_lo_export_enabled(const bool enabled,
+ const std::string& name,
+ const size_t chan) = 0;
+
+ //! Configure the LO frequency explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_rx_lo_freq() for more details.
+ // \param freq The new LO frequency
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual double
+ set_lo_freq(const double freq, const std::string& name, const size_t chan) = 0;
+
+ //! Enable/disable DC offset tracking
+ //
+ // Consult uhd::rfnoc::radio_control::set_rx_dc_offset() for more details.
+ //
+ // \param enable When true, export this LO
+ // \param chan The channel for which this setting is for
+ virtual void set_dc_offset(const bool enable, const size_t chan) = 0;
+
+ //! Set the DC offset value explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_rx_dc_offset() for more details.
+ //
+ // \param offset The DC offset value that gets used for compensation
+ // \param chan The channel for which this setting is for
+ virtual void set_dc_offset(const std::complex<double>& offset, const size_t chan) = 0;
+
+ //! Enable/disable IQ imbalance tracking
+ //
+ // Consult uhd::rfnoc::radio_control::set_rx_iq_balance() for more details.
+ //
+ // \param enable When true, export this LO
+ // \param chan The channel for which this setting is for
+ virtual void set_iq_balance(const bool enable, const size_t chan) = 0;
+
+ //! Set the I/Q imbalance correction value explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_rx_iq_balance() for more details.
+ //
+ // \param offset The DC offset value that gets used for compensation
+ // \param chan The channel for which this setting is for
+ virtual void set_iq_balance(const std::complex<double>& correction,
+ const size_t chan) = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_RX_RADIO_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_rx_streamer.h b/gr-uhd/include/gnuradio/uhd/rfnoc_rx_streamer.h
new file mode 100644
index 0000000000..fdcd15e45a
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_rx_streamer.h
@@ -0,0 +1,62 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_RX_STREAMER_H
+#define INCLUDED_GR_UHD_RFNOC_RX_STREAMER_H
+
+#include <gnuradio/sync_block.h>
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+#include <uhd/stream.hpp>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC Rx Streamer: Block to handle data flow from an RFNoC flow graph into
+ * a GNU Radio flow graph.
+ *
+ * Use this block for ingress into a GNU Radio flow graph. "Rx" is from the
+ * viewpoint of the GNU Radio flow graph. For example, if the GNU Radio flow
+ * graph is receiving samples from a radio, use this block to transport the
+ * samples into GNU Radio.
+ *
+ * Note: The input ports of this block can only connect to other RFNoC blocks.
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_rx_streamer : virtual public gr::sync_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_rx_streamer> sptr;
+
+ /*!
+ * \param graph Reference to the graph this block is connected to
+ * \param num_chans Number of input- and output ports
+ * \param stream_args These will be passed on to
+ * rfnoc_graph::create_rx_streamer, see that for details.
+ * The cpu_format and otw_format parts of these args will
+ * be used to determine the in- and output signatures of
+ * this block.
+ * \param vlen Vector length
+ * \param issue_stream_cmd_on_start If true, the streamer sends a stream
+ * command upstream.
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen = 1,
+ const bool issue_stream_cmd_on_start = true);
+
+ //! Return the unique ID associated with the underlying RFNoC streamer
+ virtual std::string get_unique_id() const = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_RX_STREAMER_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_tx_radio.h b/gr-uhd/include/gnuradio/uhd/rfnoc_tx_radio.h
new file mode 100644
index 0000000000..9fe115be29
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_tx_radio.h
@@ -0,0 +1,146 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_TX_RADIO_H
+#define INCLUDED_GR_UHD_RFNOC_TX_RADIO_H
+
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC TX Radio
+ *
+ * This wraps a radio block into GNU Radio. Note: When doing TX and RX in the
+ * same flow graph, simply crate an rfnoc_rx_radio and an rfnoc_tx_radio with
+ * the same block ID.
+ *
+ * \ingroup uhd_blk
+ */
+class GR_UHD_API rfnoc_tx_radio : virtual public rfnoc_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_tx_radio> sptr;
+
+ /*!
+ * \param graph Reference to the underlying rfnoc_graph object
+ * \param block_args Additional block arguments
+ * \param device_select Device Selection
+ * \param instance Instance Selection
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance);
+
+ //! Set the input sampling rate of the radio block
+ //
+ // Note: The actual rate of the radio will be coerced to whatever it is
+ // capable of.
+ //
+ // \param rate The new sampling rate
+ virtual double set_rate(const double rate) = 0;
+
+ //! Set the antenna for this radio
+ //
+ // \param antenna The antenna name (e.g., "RX2"). Valid name depend on the
+ // underlying hardware.
+ // \param chan The channel for which this antenna setting is for
+ virtual void set_antenna(const std::string& antenna, const size_t chan) = 0;
+
+ //! Set the TX frequency for this radio
+ //
+ // \param frequency The received frequency (e.g., 1e9)
+ // \param chan The channel for which this frequency setting is for
+ virtual double set_frequency(const double frequency, const size_t chan) = 0;
+
+ //! Configure the tune args for this RX radio
+ //
+ // \param args The new args (e.g., "mode_n=1")
+ // \param chan The channel for which this setting is for
+ virtual void set_tune_args(const ::uhd::device_addr_t& args, const size_t chan) = 0;
+
+ //! Configure the overall gain for this TX radio
+ //
+ // \param gain The new gain value (in dB)
+ // \param chan The channel for which this setting is for
+ virtual double set_gain(const double gain, const size_t chan) = 0;
+
+ //! Configure a specific gain for this RX radio
+ //
+ // \param gain The new gain value (in dB)
+ // \param name The gain stage name to set
+ // \param chan The channel for which this setting is for
+ virtual double
+ set_gain(const double gain, const std::string& name, const size_t chan) = 0;
+
+ //! Switch the gain profile for this RX radio
+ //
+ // \param profile The name of the gain profile (e.g., "default")
+ // \param chan The channel for which this setting is for
+ virtual void set_gain_profile(const std::string& profile, const size_t chan) = 0;
+
+ //! Set the analog bandwidth for this RX radio
+ //
+ // \param bandwidth The new bandwidth, in Hz
+ // \param chan The channel for which this setting is for
+ virtual double set_bandwidth(const double bandwidth, const size_t chan) = 0;
+
+ //! Set the LO source for this TX radio
+ //
+ // Note: Available sources depend on the underlying hardware.
+ //
+ // \param source The new LO source (e.g., "internal")
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual void set_lo_source(const std::string& source,
+ const std::string& name,
+ const size_t chan) = 0;
+
+ //! Enable/disable LO export for this TX radio
+ //
+ // \param enabled When true, export this LO
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual void set_lo_export_enabled(const bool enabled,
+ const std::string& name,
+ const size_t chan) = 0;
+
+ //! Configure the LO frequency explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_tx_lo_freq() for more details.
+ // \param freq The new LO frequency
+ // \param name The LO name (e.g. "LO1")
+ // \param chan The channel for which this setting is for
+ virtual double
+ set_lo_freq(const double freq, const std::string& name, const size_t chan) = 0;
+
+ //! Set the DC offset value explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_tx_dc_offset() for more details.
+ //
+ // \param offset The DC offset value that gets used for compensation
+ // \param chan The channel for which this setting is for
+ virtual void set_dc_offset(const std::complex<double>& offset, const size_t chan) = 0;
+
+ //! Set the I/Q imbalance correction value explicitly
+ //
+ // Consult uhd::rfnoc::radio_control::set_tx_iq_balance() for more details.
+ //
+ // \param offset The DC offset value that gets used for compensation
+ // \param chan The channel for which this setting is for
+ virtual void set_iq_balance(const std::complex<double>& correction,
+ const size_t chan) = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_TX_RADIO_H */
diff --git a/gr-uhd/include/gnuradio/uhd/rfnoc_tx_streamer.h b/gr-uhd/include/gnuradio/uhd/rfnoc_tx_streamer.h
new file mode 100644
index 0000000000..251575a0ef
--- /dev/null
+++ b/gr-uhd/include/gnuradio/uhd/rfnoc_tx_streamer.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_TX_STREAMER_H
+#define INCLUDED_GR_UHD_RFNOC_TX_STREAMER_H
+
+#include <gnuradio/sync_block.h>
+#include <gnuradio/uhd/api.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+#include <uhd/stream.hpp>
+
+namespace gr {
+namespace uhd {
+
+/*! RFNoC Tx Streamer: Block to handle data flow from a GNU Radio flow graph
+ * into an RFNoC flow graph.
+ *
+ * Use this block for egress from a GNU Radio flow graph. "Tx" is from the
+ * viewpoint of the GNU Radio flow graph. For example, if the GNU Radio flow
+ * graph is creating samples to be transmitted to a radio, use this block to
+ * transport the samples out of GNU Radio.
+ *
+ * Note: The output ports of this block can only connect to other RFNoC blocks.
+ *
+ * \ingroup ettus
+ */
+class GR_UHD_API rfnoc_tx_streamer : virtual public gr::sync_block
+{
+public:
+ typedef boost::shared_ptr<rfnoc_tx_streamer> sptr;
+
+ /*!
+ * \param graph Reference to the graph this block is connected to
+ * \param num_chans Number of input- and output ports
+ * \param stream_args These will be passed on to
+ * rfnoc_graph::create_tx_streamer, see that for details.
+ * The cpu_format and otw_format parts of these args will
+ * be used to determine the in- and output signatures of
+ * this block.
+ * \param vlen Vector length
+ */
+ static sptr make(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen = 1);
+
+ //! Return the unique ID associated with the underlying RFNoC streamer
+ virtual std::string get_unique_id() const = 0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_TX_STREAMER_H */
diff --git a/gr-uhd/lib/CMakeLists.txt b/gr-uhd/lib/CMakeLists.txt
index d4678013f7..e1da8b2e20 100644
--- a/gr-uhd/lib/CMakeLists.txt
+++ b/gr-uhd/lib/CMakeLists.txt
@@ -8,13 +8,29 @@
########################################################################
# Setup library
########################################################################
-add_library(gnuradio-uhd
+set(LIB_GR_UHD_SOURCES
+ amsg_source_impl.cc
usrp_block_impl.cc
- usrp_source_impl.cc
usrp_sink_impl.cc
- amsg_source_impl.cc
+ usrp_source_impl.cc
)
+if(ENABLE_UHD_RFNOC)
+ list(APPEND LIB_GR_UHD_SOURCES
+ rfnoc_block.cc
+ rfnoc_block_generic_impl.cc
+ rfnoc_ddc_impl.cc
+ rfnoc_duc_impl.cc
+ rfnoc_graph_impl.cc
+ rfnoc_rx_radio_impl.cc
+ rfnoc_rx_streamer_impl.cc
+ rfnoc_tx_radio_impl.cc
+ rfnoc_tx_streamer_impl.cc
+ )
+endif(ENABLE_UHD_RFNOC)
+
+add_library(gnuradio-uhd ${LIB_GR_UHD_SOURCES})
+
target_link_libraries(gnuradio-uhd
gnuradio-runtime
UHD::UHD
@@ -26,8 +42,6 @@ target_include_directories(gnuradio-uhd
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
)
-
-
#Add Windows DLL resource file if using MSVC
if(MSVC)
include(${CMAKE_SOURCE_DIR}/cmake/Modules/GrVersion.cmake)
diff --git a/gr-uhd/lib/rfnoc_block.cc b/gr-uhd/lib/rfnoc_block.cc
new file mode 100644
index 0000000000..7bfd5747a1
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_block.cc
@@ -0,0 +1,62 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/uhd/rfnoc_block.h>
+
+namespace gr {
+namespace uhd {
+
+/******************************************************************************
+ * Factory and Structors
+ *****************************************************************************/
+::uhd::rfnoc::noc_block_base::sptr
+rfnoc_block::make_block_ref(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const std::string& block_name,
+ const int device_select,
+ const int block_select,
+ const size_t max_ref_count)
+{
+ const std::string block_id =
+ graph->get_block_id(block_name, device_select, block_select);
+ if (block_id.empty()) {
+ throw std::runtime_error("Cannot find block!");
+ }
+
+ return graph->get_block_ref(block_id, max_ref_count);
+}
+
+rfnoc_block::rfnoc_block(::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : gr::block(
+ std::string("RFNoC::") + block_ref->get_unique_id(),
+ gr::io_signature::make(0, 0, 0), // All RFNoC blocks don't stream into GNU Radio
+ gr::io_signature::make(0, 0, 0)),
+ d_block_ref(block_ref)
+{
+}
+
+/******************************************************************************
+ * GNU Radio API
+ *****************************************************************************/
+std::string rfnoc_block::get_unique_id() const { return d_block_ref->get_unique_id(); }
+
+int rfnoc_block::general_work(int /*noutput_items*/,
+ gr_vector_int& /*ninput_items*/,
+ gr_vector_const_void_star& /*input_items*/,
+ gr_vector_void_star& /*output_items*/)
+{
+ // We should never land here
+ throw std::runtime_error("Unexpected call to general_work() in an RFNoC block!");
+ return 0;
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_block_generic_impl.cc b/gr-uhd/lib/rfnoc_block_generic_impl.cc
new file mode 100644
index 0000000000..90bdc35c55
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_block_generic_impl.cc
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_block_generic_impl.h"
+#include <gnuradio/uhd/rfnoc_graph.h>
+
+namespace gr {
+namespace uhd {
+
+/******************************************************************************
+ * Factory and Structors
+ *****************************************************************************/
+rfnoc_block_generic::sptr
+rfnoc_block_generic::make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const std::string& block_name,
+ const int device_select,
+ const int block_select)
+{
+ return gnuradio::get_initial_sptr(
+ new rfnoc_block_generic_impl(rfnoc_block::make_block_ref(
+ graph, block_args, block_name, device_select, block_select)));
+}
+
+rfnoc_block_generic_impl::rfnoc_block_generic_impl(
+ ::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : rfnoc_block(block_ref)
+{
+}
+
+rfnoc_block_generic_impl::~rfnoc_block_generic_impl() {}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_block_generic_impl.h b/gr-uhd/lib/rfnoc_block_generic_impl.h
new file mode 100644
index 0000000000..9ee7d3fb8a
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_block_generic_impl.h
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_block_generic.h>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_block_generic_impl : public rfnoc_block_generic
+{
+public:
+ rfnoc_block_generic_impl(::uhd::rfnoc::noc_block_base::sptr block_ref);
+ ~rfnoc_block_generic_impl();
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_BLOCK_GENERIC_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_ddc_impl.cc b/gr-uhd/lib/rfnoc_ddc_impl.cc
new file mode 100644
index 0000000000..7559c6acfa
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_ddc_impl.cc
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_ddc_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+namespace uhd {
+
+rfnoc_ddc::sptr rfnoc_ddc::make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance)
+{
+ return gnuradio::get_initial_sptr(new rfnoc_ddc_impl(
+ rfnoc_block::make_block_ref(graph, block_args, "DDC", device_select, instance)));
+}
+
+
+rfnoc_ddc_impl::rfnoc_ddc_impl(::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : rfnoc_block(block_ref), d_ddc_ref(get_block_ref<::uhd::rfnoc::ddc_block_control>())
+{
+}
+
+rfnoc_ddc_impl::~rfnoc_ddc_impl() {}
+
+/******************************************************************************
+ * rfnoc_ddc API
+ *****************************************************************************/
+double rfnoc_ddc_impl::set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time)
+{
+ return d_ddc_ref->set_freq(freq, chan, time);
+}
+
+double rfnoc_ddc_impl::set_output_rate(const double rate, const size_t chan)
+{
+ return d_ddc_ref->set_output_rate(rate, chan);
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_ddc_impl.h b/gr-uhd/lib/rfnoc_ddc_impl.h
new file mode 100644
index 0000000000..2cf3a89c42
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_ddc_impl.h
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_DDC_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_DDC_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_ddc.h>
+#include <uhd/rfnoc/ddc_block_control.hpp>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_ddc_impl : public rfnoc_ddc
+{
+public:
+ rfnoc_ddc_impl(::uhd::rfnoc::noc_block_base::sptr block_ref);
+ ~rfnoc_ddc_impl();
+
+ /*** API *****************************************************************/
+ double set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time = ::uhd::time_spec_t::ASAP);
+ double set_output_rate(const double rate, const size_t chan);
+
+private:
+ ::uhd::rfnoc::ddc_block_control::sptr d_ddc_ref;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_DDC_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_duc_impl.cc b/gr-uhd/lib/rfnoc_duc_impl.cc
new file mode 100644
index 0000000000..c77f2313b4
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_duc_impl.cc
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_duc_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+namespace uhd {
+
+rfnoc_duc::sptr rfnoc_duc::make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance)
+{
+ return gnuradio::get_initial_sptr(new rfnoc_duc_impl(
+ rfnoc_block::make_block_ref(graph, block_args, "DUC", device_select, instance)));
+}
+
+
+rfnoc_duc_impl::rfnoc_duc_impl(::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : rfnoc_block(block_ref), d_duc_ref(get_block_ref<::uhd::rfnoc::duc_block_control>())
+{
+}
+
+rfnoc_duc_impl::~rfnoc_duc_impl() {}
+
+/******************************************************************************
+ * rfnoc_duc API
+ *****************************************************************************/
+double rfnoc_duc_impl::set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time)
+{
+ return d_duc_ref->set_freq(freq, chan, time);
+}
+
+double rfnoc_duc_impl::set_input_rate(const double rate, const size_t chan)
+{
+ return d_duc_ref->set_input_rate(rate, chan);
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_duc_impl.h b/gr-uhd/lib/rfnoc_duc_impl.h
new file mode 100644
index 0000000000..1bf1306e31
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_duc_impl.h
@@ -0,0 +1,37 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_DUC_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_DUC_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_duc.h>
+#include <uhd/rfnoc/duc_block_control.hpp>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_duc_impl : public rfnoc_duc
+{
+public:
+ rfnoc_duc_impl(::uhd::rfnoc::noc_block_base::sptr block_ref);
+ ~rfnoc_duc_impl();
+
+ /*** API *****************************************************************/
+ double set_freq(const double freq,
+ const size_t chan,
+ const ::uhd::time_spec_t time = ::uhd::time_spec_t::ASAP);
+ double set_input_rate(const double rate, const size_t chan);
+
+private:
+ ::uhd::rfnoc::duc_block_control::sptr d_duc_ref;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_DUC_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_graph_impl.cc b/gr-uhd/lib/rfnoc_graph_impl.cc
new file mode 100644
index 0000000000..436faeedea
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_graph_impl.cc
@@ -0,0 +1,214 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gr_uhd_common.h"
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+#include <uhd/rfnoc/mb_controller.hpp>
+#include <uhd/rfnoc_graph.hpp>
+#include <unordered_map>
+#include <boost/make_shared.hpp>
+#include <atomic>
+#include <stdexcept>
+
+using ::uhd::rfnoc::block_id_t;
+using namespace gr::uhd;
+using namespace ::uhd;
+
+
+class rfnoc_graph_impl : public rfnoc_graph
+{
+public:
+ rfnoc_graph_impl(const device_addr_t& dev_addr)
+ : _graph(::uhd::rfnoc::rfnoc_graph::make(dev_addr))
+ {
+ // nop
+ }
+
+ void connect(const std::string& src_block_id,
+ const size_t src_block_port,
+ const std::string& dst_block_id,
+ const size_t dst_block_port,
+ const bool skip_property_propagation)
+ {
+ if (_tx_streamers.count(src_block_id)) {
+ if (_rx_streamers.count(dst_block_id)) {
+ throw std::runtime_error("Cannot connect RFNoC streamers directly!");
+ }
+ _graph->connect(_tx_streamers.at(src_block_id),
+ src_block_port,
+ block_id_t(dst_block_id),
+ dst_block_port);
+ return;
+ }
+ if (_rx_streamers.count(dst_block_id)) {
+ _graph->connect(src_block_id,
+ src_block_port,
+ _rx_streamers.at(dst_block_id),
+ dst_block_port);
+ return;
+ }
+
+ _graph->connect(block_id_t(src_block_id),
+ src_block_port,
+ block_id_t(dst_block_id),
+ dst_block_port);
+ }
+
+ void connect(const std::string& block1,
+ const std::string& block2,
+ bool skip_property_propagation)
+ {
+ connect(block1, 0, block2, 0, skip_property_propagation);
+ }
+
+ void connect(rfnoc_block::sptr src_block,
+ const size_t src_block_port,
+ rfnoc_block::sptr dst_block,
+ const size_t dst_block_port,
+ const bool skip_property_propagation)
+ {
+ connect(src_block->get_unique_id(),
+ src_block_port,
+ dst_block->get_unique_id(),
+ dst_block_port,
+ skip_property_propagation);
+ }
+
+
+ ::uhd::rx_streamer::sptr create_rx_streamer(const size_t num_ports,
+ const stream_args_t& args)
+ {
+ auto streamer = _graph->create_rx_streamer(num_ports, args);
+ const std::string streamer_id =
+ std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(streamer)->get_unique_id();
+ _rx_streamers.insert({ streamer_id, streamer });
+ return streamer;
+ }
+
+ ::uhd::tx_streamer::sptr create_tx_streamer(const size_t num_ports,
+ const stream_args_t& args)
+ {
+ auto streamer = _graph->create_tx_streamer(num_ports, args);
+ const std::string streamer_id =
+ std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(streamer)->get_unique_id();
+ _tx_streamers.insert({ streamer_id, streamer });
+ return streamer;
+ }
+
+ void commit()
+ {
+ if (!_commit_called.exchange(true)) {
+ _graph->commit();
+ }
+ }
+
+ std::string get_block_id(const std::string& block_name,
+ const int device_select,
+ const int block_select)
+ {
+ std::string block_hint = block_name;
+ if (device_select >= 0) {
+ block_hint = str(boost::format("%d/%s") % device_select % block_hint);
+ }
+ if (block_select >= 0) {
+ block_hint = str(boost::format("%s#%d") % block_hint % block_select);
+ }
+
+ auto block_ids = _graph->find_blocks(block_hint);
+ if (block_ids.empty()) {
+ return "";
+ }
+
+ // If the hint produced a unique hit, then we return that
+ if (block_ids.size() == 1) {
+ return block_ids.front().to_string();
+ }
+
+ // If the hint produced multiple hits, then we default to one that was
+ // not yet acquired. If that fails, return any one.
+ std::lock_guard<std::mutex> l(_block_ref_mutex);
+ for (const auto& block_id : block_ids) {
+ const std::string block_id_str = block_id.to_string();
+ if (!_acqd_block_refs.count(block_id_str)) {
+ return block_id_str;
+ }
+ }
+ return block_ids.front().to_string();
+ }
+
+ void set_time_source(const std::string& source, const size_t mb_index)
+ {
+ _graph->get_mb_controller(mb_index)->set_time_source(source);
+ }
+
+ void set_clock_source(const std::string& source, const size_t mb_index)
+ {
+ _graph->get_mb_controller(mb_index)->set_clock_source(source);
+ }
+
+ ::uhd::rfnoc::noc_block_base::sptr get_block_ref(const std::string& block_id,
+ const size_t max_ref_count)
+ {
+ std::lock_guard<std::mutex> l(_block_ref_mutex);
+ if (max_ref_count == 0) {
+ throw std::runtime_error("Invalid max_ref_count 0!");
+ }
+
+ auto block_ref = _graph->get_block(block_id_t(block_id));
+ const std::string real_block_id = block_ref->get_unique_id();
+
+ // If this is the first time we encounter this block ID, create a ref
+ // counter for it
+ if (!_acqd_block_refs.count(real_block_id)) {
+ _acqd_block_refs.insert({ real_block_id, 0 });
+ }
+ // Make sure the max ref count limit is set. If it already exists,
+ // decrease it if max_ref_count is smaller than what we already have.
+ if (!_max_ref_count.count(real_block_id)) {
+ _max_ref_count.insert({ real_block_id, max_ref_count });
+ } else {
+ _max_ref_count[real_block_id] =
+ std::min(max_ref_count, _max_ref_count[real_block_id]);
+ }
+ // Now check we haven't exceeded the ref count limit
+ if (_acqd_block_refs.at(real_block_id) >= _max_ref_count.at(real_block_id)) {
+ throw std::runtime_error(
+ std::string("Attempting to get another reference to block ") +
+ real_block_id);
+ }
+ // Increase ref counter for this block ID
+ _acqd_block_refs[real_block_id]++;
+
+ // And Bob's your uncle
+ return block_ref;
+ }
+
+
+private:
+ std::atomic<bool> _commit_called{ false };
+ ::uhd::rfnoc::rfnoc_graph::sptr _graph;
+
+ std::unordered_map<std::string, ::uhd::rx_streamer::sptr> _rx_streamers;
+ std::unordered_map<std::string, ::uhd::tx_streamer::sptr> _tx_streamers;
+
+ std::mutex _block_ref_mutex;
+ std::unordered_map<std::string, size_t> _acqd_block_refs;
+ std::unordered_map<std::string, size_t> _max_ref_count;
+};
+
+
+rfnoc_graph::sptr rfnoc_graph::make(const device_addr_t& dev_addr)
+{
+ check_abi();
+ return boost::make_shared<rfnoc_graph_impl>(dev_addr);
+}
diff --git a/gr-uhd/lib/rfnoc_rx_radio_impl.cc b/gr-uhd/lib/rfnoc_rx_radio_impl.cc
new file mode 100644
index 0000000000..3012e0fbf7
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_rx_radio_impl.cc
@@ -0,0 +1,133 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_rx_radio_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+namespace uhd {
+
+constexpr size_t MAX_RADIO_REFS = 2; // One for RX, one for TX
+
+rfnoc_rx_radio::sptr rfnoc_rx_radio::make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance)
+{
+ return gnuradio::get_initial_sptr(new rfnoc_rx_radio_impl(rfnoc_block::make_block_ref(
+ graph, block_args, "Radio", device_select, instance, MAX_RADIO_REFS)));
+}
+
+
+rfnoc_rx_radio_impl::rfnoc_rx_radio_impl(::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : rfnoc_block(block_ref), d_radio_ref(get_block_ref<::uhd::rfnoc::radio_control>())
+{
+}
+
+rfnoc_rx_radio_impl::~rfnoc_rx_radio_impl() {}
+
+/******************************************************************************
+ * rfnoc_rx_radio API
+ *****************************************************************************/
+double rfnoc_rx_radio_impl::set_rate(const double rate)
+{
+ return d_radio_ref->set_rate(rate);
+}
+
+void rfnoc_rx_radio_impl::set_antenna(const std::string& antenna, const size_t chan)
+{
+ return d_radio_ref->set_rx_antenna(antenna, chan);
+}
+
+double rfnoc_rx_radio_impl::set_frequency(const double frequency, const size_t chan)
+{
+ return d_radio_ref->set_rx_frequency(frequency, chan);
+}
+
+void rfnoc_rx_radio_impl::set_tune_args(const ::uhd::device_addr_t& args,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_tune_args(args, chan);
+}
+
+double rfnoc_rx_radio_impl::set_gain(const double gain, const size_t chan)
+{
+ return d_radio_ref->set_rx_gain(gain, chan);
+}
+
+double rfnoc_rx_radio_impl::set_gain(const double gain,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_gain(gain, name, chan);
+}
+
+void rfnoc_rx_radio_impl::set_agc(const bool enable, const size_t chan)
+{
+ return d_radio_ref->set_rx_agc(enable, chan);
+}
+
+void rfnoc_rx_radio_impl::set_gain_profile(const std::string& profile, const size_t chan)
+{
+ return d_radio_ref->set_rx_gain_profile(profile, chan);
+}
+
+double rfnoc_rx_radio_impl::set_bandwidth(const double bandwidth, const size_t chan)
+{
+ return d_radio_ref->set_rx_bandwidth(bandwidth, chan);
+}
+
+void rfnoc_rx_radio_impl::set_lo_source(const std::string& source,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_lo_source(source, name, chan);
+}
+
+void rfnoc_rx_radio_impl::set_lo_export_enabled(const bool enabled,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_lo_export_enabled(enabled, name, chan);
+}
+
+double rfnoc_rx_radio_impl::set_lo_freq(const double freq,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_lo_freq(freq, name, chan);
+}
+
+void rfnoc_rx_radio_impl::set_dc_offset(const bool enable, const size_t chan)
+{
+ return d_radio_ref->set_rx_dc_offset(enable, chan);
+}
+
+void rfnoc_rx_radio_impl::set_dc_offset(const std::complex<double>& offset,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_dc_offset(offset, chan);
+}
+
+void rfnoc_rx_radio_impl::set_iq_balance(const bool enable, const size_t chan)
+{
+ return d_radio_ref->set_rx_iq_balance(enable, chan);
+}
+
+void rfnoc_rx_radio_impl::set_iq_balance(const std::complex<double>& correction,
+ const size_t chan)
+{
+ return d_radio_ref->set_rx_iq_balance(correction, chan);
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_rx_radio_impl.h b/gr-uhd/lib/rfnoc_rx_radio_impl.h
new file mode 100644
index 0000000000..5cffaf1813
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_rx_radio_impl.h
@@ -0,0 +1,51 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_RX_RADIO_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_RX_RADIO_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_rx_radio.h>
+#include <uhd/rfnoc/radio_control.hpp>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_rx_radio_impl : public rfnoc_rx_radio
+{
+public:
+ rfnoc_rx_radio_impl(::uhd::rfnoc::noc_block_base::sptr block_ref);
+ ~rfnoc_rx_radio_impl();
+
+ /*** API *****************************************************************/
+ double set_rate(const double rate);
+ void set_antenna(const std::string& antenna, const size_t chan);
+ double set_frequency(const double frequency, const size_t chan);
+ void set_tune_args(const ::uhd::device_addr_t& args, const size_t chan);
+ double set_gain(const double gain, const size_t chan);
+ double set_gain(const double gain, const std::string& name, const size_t chan);
+ void set_agc(const bool enable, const size_t chan);
+ void set_gain_profile(const std::string& profile, const size_t chan);
+ double set_bandwidth(const double bandwidth, const size_t chan);
+ void
+ set_lo_source(const std::string& source, const std::string& name, const size_t chan);
+ void
+ set_lo_export_enabled(const bool enabled, const std::string& name, const size_t chan);
+ double set_lo_freq(const double freq, const std::string& name, const size_t chan);
+ void set_dc_offset(const bool enable, const size_t chan);
+ void set_dc_offset(const std::complex<double>& offset, const size_t chan);
+ void set_iq_balance(const bool enable, const size_t chan);
+ void set_iq_balance(const std::complex<double>& correction, const size_t chan);
+
+private:
+ ::uhd::rfnoc::radio_control::sptr d_radio_ref;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_RX_RADIO_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_rx_streamer_impl.cc b/gr-uhd/lib/rfnoc_rx_streamer_impl.cc
new file mode 100644
index 0000000000..ee7e854cde
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_rx_streamer_impl.cc
@@ -0,0 +1,192 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gr_uhd_common.h"
+#include "rfnoc_rx_streamer_impl.h"
+#include <gnuradio/io_signature.h>
+#include <uhd/convert.hpp>
+#include <uhd/rfnoc/node.hpp>
+
+const pmt::pmt_t EOB_KEY = pmt::string_to_symbol("rx_eob");
+const pmt::pmt_t CMD_TIME_KEY = pmt::mp("time");
+const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan");
+const pmt::pmt_t MSG_PORT_RFNOC = pmt::mp("rfnoc");
+
+namespace gr {
+namespace uhd {
+
+/******************************************************************************
+ * Factory and Structors
+ *****************************************************************************/
+rfnoc_rx_streamer::sptr rfnoc_rx_streamer::make(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen,
+ const bool issue_stream_cmd_on_start)
+{
+ return gnuradio::get_initial_sptr(new rfnoc_rx_streamer_impl(
+ graph, num_chans, stream_args, vlen, issue_stream_cmd_on_start));
+}
+
+
+rfnoc_rx_streamer_impl::rfnoc_rx_streamer_impl(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen,
+ const bool issue_stream_cmd_on_start)
+ : gr::sync_block(
+ "rfnoc_rx_streamer",
+ gr::io_signature::make(0, 0, 0),
+ gr::io_signature::make(
+ num_chans,
+ num_chans,
+ ::uhd::convert::get_bytes_per_item(stream_args.cpu_format) * vlen)),
+ d_num_chans(num_chans),
+ d_itemsize(::uhd::convert::get_bytes_per_item(stream_args.cpu_format)),
+ d_vlen(vlen),
+ d_graph(graph),
+ d_stream_args(stream_args),
+ d_streamer(graph->create_rx_streamer(num_chans, stream_args)),
+ d_unique_id(
+ std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(d_streamer)->get_unique_id()),
+ d_issue_stream_cmd_on_start(issue_stream_cmd_on_start)
+{
+ // nop
+}
+
+rfnoc_rx_streamer_impl::~rfnoc_rx_streamer_impl() {}
+
+
+/******************************************************************************
+ * GNU Radio API
+ *****************************************************************************/
+bool rfnoc_rx_streamer_impl::check_topology(int, int)
+{
+ GR_LOG_DEBUG(d_logger, "Committing graph...");
+ d_graph->commit();
+ return true;
+}
+
+bool rfnoc_rx_streamer_impl::start()
+{
+ if (d_issue_stream_cmd_on_start) {
+ // Start the streamers
+ ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ if (d_start_time_set) {
+ stream_cmd.stream_now = false;
+ stream_cmd.time_spec = d_start_time;
+ d_start_time_set = false;
+ } else {
+ stream_cmd.stream_now = true;
+ }
+
+ GR_LOG_DEBUG(d_logger, "Sending start stream command...");
+ d_streamer->issue_stream_cmd(stream_cmd);
+ } else {
+ GR_LOG_DEBUG(d_logger, "Starting RX streamer without stream command...");
+ }
+ return true;
+}
+
+bool rfnoc_rx_streamer_impl::stop()
+{
+ // If we issue a stream command on start, we also issue it on stop
+ if (d_issue_stream_cmd_on_start) {
+ ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ d_streamer->issue_stream_cmd(stream_cmd);
+ }
+ flush();
+ return true;
+}
+
+int rfnoc_rx_streamer_impl::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ const size_t max_num_items_to_rx = noutput_items * d_vlen;
+ const size_t num_items_recvd =
+ d_streamer->recv(output_items, max_num_items_to_rx, d_metadata, d_timeout);
+
+ const size_t num_vecs_recvd = num_items_recvd / d_vlen;
+ if (num_items_recvd % d_vlen) {
+ // TODO: Create a fix for this. What will happen is that a partial
+ // vector will be received, but it won't be available in the output_items.
+ // We need to store the partial vector, and prepend it to the next
+ // run.
+ GR_LOG_WARN(d_logger, "Received fractional vector! Expect signal fragmentation.");
+ }
+
+ using ::uhd::rx_metadata_t;
+ switch (d_metadata.error_code) {
+ case rx_metadata_t::ERROR_CODE_NONE:
+ break;
+
+ case rx_metadata_t::ERROR_CODE_TIMEOUT:
+ // its ok to timeout, perhaps the user is doing finite streaming
+ GR_LOG_DEBUG(d_logger, "UHD recv() call timed out.");
+ break;
+
+ case rx_metadata_t::ERROR_CODE_OVERFLOW:
+ // Not much we can do about overruns here, and they get signalled via the
+ // UHD logging interface
+ break;
+
+ default:
+ GR_LOG_WARN(
+ d_logger,
+ str(boost::format("RFNoC Streamer block received error %s (Code: 0x%x)") %
+ d_metadata.strerror() % d_metadata.error_code));
+ }
+
+ if (d_metadata.end_of_burst) {
+ for (size_t i = 0; i < output_items.size(); i++) {
+ add_item_tag(i, nitems_written(i) + num_vecs_recvd - 1, EOB_KEY, pmt::PMT_T);
+ }
+ }
+
+ return num_vecs_recvd;
+}
+
+/******************************************************************************
+ * rfnoc_rx_streamer API
+ *****************************************************************************/
+void rfnoc_rx_streamer_impl::set_start_time(const ::uhd::time_spec_t& time)
+{
+ d_start_time_set = true;
+ d_start_time = time;
+}
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+void rfnoc_rx_streamer_impl::flush()
+{
+ constexpr size_t nbytes = 4096;
+ const size_t nchan = d_streamer->get_num_channels();
+ std::vector<std::vector<uint8_t>> buffs(nchan, std::vector<uint8_t>(nbytes));
+
+ gr_vector_void_star outputs;
+ for (size_t i = 0; i < nchan; i++) {
+ outputs.push_back(&buffs[i].front());
+ }
+
+ const size_t itemsize = output_signature()->sizeof_stream_item(0);
+ while (true) {
+ d_streamer->recv(outputs, nbytes / itemsize / d_vlen, d_metadata, 0.0);
+ if (d_metadata.error_code != ::uhd::rx_metadata_t::ERROR_CODE_NONE) {
+ break;
+ }
+ }
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_rx_streamer_impl.h b/gr-uhd/lib/rfnoc_rx_streamer_impl.h
new file mode 100644
index 0000000000..f2da43b569
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_rx_streamer_impl.h
@@ -0,0 +1,73 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_RX_STREAMER_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_RX_STREAMER_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_rx_streamer.h>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_rx_streamer_impl : public rfnoc_rx_streamer
+{
+public:
+ rfnoc_rx_streamer_impl(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen,
+ const bool issue_stream_cmd_on_start);
+ ~rfnoc_rx_streamer_impl();
+
+ std::string get_unique_id() const override { return d_unique_id; }
+
+ /***** API ***************************************************************/
+ void set_start_time(const ::uhd::time_spec_t& time);
+
+ /***** GNU Radio API *****************************************************/
+ bool check_topology(int, int) override;
+ bool start() override;
+ bool stop() override;
+ int work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items) override;
+
+private:
+ void flush();
+
+ //! Number of streaming channels
+ const size_t d_num_chans;
+ //! Bytes per item (e.g. 4 for sc16)
+ const size_t d_itemsize;
+ //! Input vector length
+ const size_t d_vlen;
+ //! Reference to the underlying graph
+ rfnoc_graph::sptr d_graph;
+ //! Stream args
+ ::uhd::stream_args_t d_stream_args;
+ //! Reference to the actual streamer
+ ::uhd::rx_streamer::sptr d_streamer;
+ //! Copy of the streamer's block ID
+ const std::string d_unique_id;
+ //! Stash for the TX metadata
+ ::uhd::rx_metadata_t d_metadata;
+ //! RX timeout value
+ double d_timeout = 1.0;
+ //! True if the stream should immediately start with the flow graph without
+ // external prompting
+ const bool d_issue_stream_cmd_on_start;
+ //! True if d_start_time holds a value we need to process
+ bool d_start_time_set = false;
+ //! A start time for the next stream command
+ ::uhd::time_spec_t d_start_time;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_RX_STREAMER_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_tx_radio_impl.cc b/gr-uhd/lib/rfnoc_tx_radio_impl.cc
new file mode 100644
index 0000000000..531eb75396
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_tx_radio_impl.cc
@@ -0,0 +1,119 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_tx_radio_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+namespace uhd {
+
+constexpr size_t MAX_RADIO_REFS = 2; // One for RX, one for TX
+
+rfnoc_tx_radio::sptr rfnoc_tx_radio::make(rfnoc_graph::sptr graph,
+ const ::uhd::device_addr_t& block_args,
+ const int device_select,
+ const int instance)
+{
+ return gnuradio::get_initial_sptr(new rfnoc_tx_radio_impl(rfnoc_block::make_block_ref(
+ graph, block_args, "Radio", device_select, instance, MAX_RADIO_REFS)));
+}
+
+
+rfnoc_tx_radio_impl::rfnoc_tx_radio_impl(::uhd::rfnoc::noc_block_base::sptr block_ref)
+ : rfnoc_block(block_ref),
+ d_wrapped_ref(std::dynamic_pointer_cast<::uhd::rfnoc::radio_control>(block_ref))
+{
+}
+
+rfnoc_tx_radio_impl::~rfnoc_tx_radio_impl() {}
+
+/******************************************************************************
+ * rfnoc_tx_radio API
+ *****************************************************************************/
+double rfnoc_tx_radio_impl::set_rate(const double rate)
+{
+ return d_wrapped_ref->set_rate(rate);
+}
+
+void rfnoc_tx_radio_impl::set_antenna(const std::string& antenna, const size_t chan)
+{
+ return d_wrapped_ref->set_tx_antenna(antenna, chan);
+}
+
+double rfnoc_tx_radio_impl::set_frequency(const double frequency, const size_t chan)
+{
+ return d_wrapped_ref->set_tx_frequency(frequency, chan);
+}
+
+void rfnoc_tx_radio_impl::set_tune_args(const ::uhd::device_addr_t& args,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_tune_args(args, chan);
+}
+
+double rfnoc_tx_radio_impl::set_gain(const double gain, const size_t chan)
+{
+ return d_wrapped_ref->set_tx_gain(gain, chan);
+}
+
+double rfnoc_tx_radio_impl::set_gain(const double gain,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_gain(gain, name, chan);
+}
+
+void rfnoc_tx_radio_impl::set_gain_profile(const std::string& profile, const size_t chan)
+{
+ return d_wrapped_ref->set_tx_gain_profile(profile, chan);
+}
+
+double rfnoc_tx_radio_impl::set_bandwidth(const double bandwidth, const size_t chan)
+{
+ return d_wrapped_ref->set_tx_bandwidth(bandwidth, chan);
+}
+
+void rfnoc_tx_radio_impl::set_lo_source(const std::string& source,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_lo_source(source, name, chan);
+}
+
+void rfnoc_tx_radio_impl::set_lo_export_enabled(const bool enabled,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_lo_export_enabled(enabled, name, chan);
+}
+
+double rfnoc_tx_radio_impl::set_lo_freq(const double freq,
+ const std::string& name,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_lo_freq(freq, name, chan);
+}
+
+void rfnoc_tx_radio_impl::set_dc_offset(const std::complex<double>& offset,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_dc_offset(offset, chan);
+}
+
+void rfnoc_tx_radio_impl::set_iq_balance(const std::complex<double>& correction,
+ const size_t chan)
+{
+ return d_wrapped_ref->set_tx_iq_balance(correction, chan);
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_tx_radio_impl.h b/gr-uhd/lib/rfnoc_tx_radio_impl.h
new file mode 100644
index 0000000000..1738c70e5a
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_tx_radio_impl.h
@@ -0,0 +1,48 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_TX_RADIO_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_TX_RADIO_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_tx_radio.h>
+#include <uhd/rfnoc/radio_control.hpp>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_tx_radio_impl : public rfnoc_tx_radio
+{
+public:
+ rfnoc_tx_radio_impl(::uhd::rfnoc::noc_block_base::sptr block_ref);
+ ~rfnoc_tx_radio_impl();
+
+ /*** API *****************************************************************/
+ double set_rate(const double rate);
+ void set_antenna(const std::string& antenna, const size_t chan);
+ double set_frequency(const double frequency, const size_t chan);
+ void set_tune_args(const ::uhd::device_addr_t& args, const size_t chan);
+ double set_gain(const double gain, const size_t chan);
+ double set_gain(const double gain, const std::string& name, const size_t chan);
+ void set_gain_profile(const std::string& profile, const size_t chan);
+ double set_bandwidth(const double bandwidth, const size_t chan);
+ void
+ set_lo_source(const std::string& source, const std::string& name, const size_t chan);
+ void
+ set_lo_export_enabled(const bool enabled, const std::string& name, const size_t chan);
+ double set_lo_freq(const double freq, const std::string& name, const size_t chan);
+ void set_dc_offset(const std::complex<double>& offset, const size_t chan);
+ void set_iq_balance(const std::complex<double>& correction, const size_t chan);
+
+private:
+ ::uhd::rfnoc::radio_control::sptr d_wrapped_ref;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_TX_RADIO_IMPL_H */
diff --git a/gr-uhd/lib/rfnoc_tx_streamer_impl.cc b/gr-uhd/lib/rfnoc_tx_streamer_impl.cc
new file mode 100644
index 0000000000..9a12a8b3f2
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_tx_streamer_impl.cc
@@ -0,0 +1,93 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rfnoc_tx_streamer_impl.h"
+#include <gnuradio/io_signature.h>
+#include <uhd/convert.hpp>
+#include <uhd/rfnoc/node.hpp>
+
+namespace gr {
+namespace uhd {
+
+/******************************************************************************
+ * Factory and Structors
+ *****************************************************************************/
+rfnoc_tx_streamer::sptr rfnoc_tx_streamer::make(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen)
+{
+ return gnuradio::get_initial_sptr(
+ new rfnoc_tx_streamer_impl(graph, num_chans, stream_args, vlen));
+}
+
+
+rfnoc_tx_streamer_impl::rfnoc_tx_streamer_impl(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen)
+ : gr::sync_block(
+ "rfnoc_tx_streamer",
+ gr::io_signature::make(
+ num_chans,
+ num_chans,
+ ::uhd::convert::get_bytes_per_item(stream_args.cpu_format) * vlen),
+ gr::io_signature::make(0, 0, 0)),
+ d_num_chans(num_chans),
+ d_itemsize(::uhd::convert::get_bytes_per_item(stream_args.cpu_format)),
+ d_vlen(vlen),
+ d_graph(graph),
+ d_stream_args(stream_args),
+ d_streamer(graph->create_tx_streamer(num_chans, stream_args)),
+ d_unique_id(
+ std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(d_streamer)->get_unique_id())
+{
+ // nop
+}
+
+rfnoc_tx_streamer_impl::~rfnoc_tx_streamer_impl() {}
+
+/******************************************************************************
+ * GNU Radio API
+ *****************************************************************************/
+bool rfnoc_tx_streamer_impl::check_topology(int, int)
+{
+ GR_LOG_DEBUG(d_logger, "Committing graph...");
+ d_graph->commit();
+ return true;
+}
+
+/******************************************************************************
+ * GNU Radio API
+ *****************************************************************************/
+int rfnoc_tx_streamer_impl::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ const size_t num_items_to_send = noutput_items * d_vlen;
+ const size_t num_items_sent =
+ d_streamer->send(input_items, num_items_to_send, d_metadata, d_timeout);
+ const size_t num_vecs_sent = num_items_sent / d_vlen;
+
+ if (num_items_sent % d_vlen) {
+ // TODO: Create a fix for this. What will happen is that a partial
+ // vector will be sent, but it won't be consumed from the input_items.
+ // We need to store the offset (what fraction of the vector was sent)
+ // and tx that first.
+ GR_LOG_WARN(d_logger, "Sent fractional vector! Expect signal fragmentation.");
+ }
+
+ return num_vecs_sent;
+}
+
+} /* namespace uhd */
+} /* namespace gr */
diff --git a/gr-uhd/lib/rfnoc_tx_streamer_impl.h b/gr-uhd/lib/rfnoc_tx_streamer_impl.h
new file mode 100644
index 0000000000..36819b13d8
--- /dev/null
+++ b/gr-uhd/lib/rfnoc_tx_streamer_impl.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 Ettus Research, a National Instruments Brand.
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_GR_UHD_RFNOC_TX_STREAMER_IMPL_H
+#define INCLUDED_GR_UHD_RFNOC_TX_STREAMER_IMPL_H
+
+#include <gnuradio/uhd/rfnoc_tx_streamer.h>
+
+namespace gr {
+namespace uhd {
+
+class rfnoc_tx_streamer_impl : public rfnoc_tx_streamer
+{
+public:
+ rfnoc_tx_streamer_impl(rfnoc_graph::sptr graph,
+ const size_t num_chans,
+ const ::uhd::stream_args_t& stream_args,
+ const size_t vlen);
+ ~rfnoc_tx_streamer_impl();
+
+ /***** API ***************************************************************/
+ std::string get_unique_id() const override { return d_unique_id; }
+
+ /***** GNU Radio API *****************************************************/
+ bool check_topology(int, int) override;
+ int work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items) override;
+
+private:
+ //! Number of streaming channels
+ const size_t d_num_chans;
+ //! Bytes per item (e.g. 4 for sc16)
+ const size_t d_itemsize;
+ //! Input vector length
+ const size_t d_vlen;
+ //! Reference to the underlying graph
+ rfnoc_graph::sptr d_graph;
+ //! Stream args
+ ::uhd::stream_args_t d_stream_args;
+ //! Reference to the actual streamer
+ ::uhd::tx_streamer::sptr d_streamer;
+ //! Copy of the streamer's block ID
+ const std::string d_unique_id;
+ //! Stash for the TX metadata
+ ::uhd::tx_metadata_t d_metadata;
+ //! TX timeout value
+ double d_timeout = 1.0;
+};
+
+} // namespace uhd
+} // namespace gr
+
+#endif /* INCLUDED_GR_UHD_RFNOC_TX_STREAMER_IMPL_H */
diff --git a/gr-uhd/swig/CMakeLists.txt b/gr-uhd/swig/CMakeLists.txt
index f25d816b1d..e4decbdef1 100644
--- a/gr-uhd/swig/CMakeLists.txt
+++ b/gr-uhd/swig/CMakeLists.txt
@@ -12,6 +12,9 @@ include(GrPython)
include(GrSwig)
set(GR_SWIG_FLAGS -DGR_HAVE_UHD) #needed to parse uhd_swig.i
+if(ENABLE_UHD_RFNOC)
+ set(GR_SWIG_FLAGS ${GR_SWIG_FLAGS} -DGR_HAVE_RFNOC)
+endif(ENABLE_UHD_RFNOC)
set(GR_SWIG_INCLUDE_DIRS $<TARGET_PROPERTY:runtime_swig,INCLUDE_DIRECTORIES>)
set(GR_SWIG_TARGET_DEPS runtime_swig)
diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i
index 68941248fb..f07f3a41f8 100644
--- a/gr-uhd/swig/uhd_swig.i
+++ b/gr-uhd/swig/uhd_swig.i
@@ -35,6 +35,14 @@
%ignore gr::uhd::usrp_sink::get_device;
%ignore gr::uhd::usrp_source::get_device;
+#ifdef GR_HAVE_RFNOC
+%ignore gr::uhd::rfnoc_graph::create_rx_streamer;
+%ignore gr::uhd::rfnoc_graph::create_tx_streamer;
+%ignore gr::uhd::rfnoc_graph::get_block_ref;
+%ignore gr::uhd::rfnoc_block::get_block_ref;
+%ignore gr::uhd::rfnoc_block::make_block_ref;
+#endif
+
////////////////////////////////////////////////////////////////////////
// block headers
////////////////////////////////////////////////////////////////////////
@@ -44,6 +52,20 @@
#include <gnuradio/uhd/amsg_source.h>
%}
+#ifdef GR_HAVE_RFNOC
+%{
+#include <gnuradio/uhd/rfnoc_block.h>
+#include <gnuradio/uhd/rfnoc_graph.h>
+#include <gnuradio/uhd/rfnoc_tx_streamer.h>
+#include <gnuradio/uhd/rfnoc_rx_streamer.h>
+#include <gnuradio/uhd/rfnoc_block_generic.h>
+#include <gnuradio/uhd/rfnoc_ddc.h>
+#include <gnuradio/uhd/rfnoc_duc.h>
+#include <gnuradio/uhd/rfnoc_rx_radio.h>
+#include <gnuradio/uhd/rfnoc_tx_radio.h>
+%}
+#endif
+
%include "gnuradio/uhd/usrp_block.h"
////////////////////////////////////////////////////////////////////////
@@ -186,20 +208,47 @@
%include <gnuradio/uhd/usrp_sink.h>
%include <gnuradio/uhd/amsg_source.h>
+#ifdef GR_HAVE_RFNOC
+%include <gnuradio/uhd/rfnoc_graph.h>
+%include <gnuradio/uhd/rfnoc_block.h>
+%include <gnuradio/uhd/rfnoc_tx_streamer.h>
+%include <gnuradio/uhd/rfnoc_rx_streamer.h>
+%include <gnuradio/uhd/rfnoc_block_generic.h>
+%include <gnuradio/uhd/rfnoc_ddc.h>
+%include <gnuradio/uhd/rfnoc_duc.h>
+%include <gnuradio/uhd/rfnoc_rx_radio.h>
+%include <gnuradio/uhd/rfnoc_tx_radio.h>
+#endif
+
GR_SWIG_BLOCK_MAGIC2(uhd, usrp_source)
GR_SWIG_BLOCK_MAGIC2(uhd, usrp_sink)
GR_SWIG_BLOCK_MAGIC2(uhd, amsg_source)
+#ifdef GR_HAVE_RFNOC
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_graph)
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_tx_streamer);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_rx_streamer);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_block_generic);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_ddc);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_duc);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_rx_radio);
+GR_SWIG_BLOCK_MAGIC2(uhd, rfnoc_tx_radio);
+#endif
+
+
////////////////////////////////////////////////////////////////////////
// device discovery (no need to %include device.hpp)
////////////////////////////////////////////////////////////////////////
%{
-static uhd::device_addrs_t find_devices_raw(const uhd::device_addr_t &dev_addr = uhd::device_addr_t()){
+static uhd::device_addrs_t find_devices_raw(
+ const uhd::device_addr_t &dev_addr = uhd::device_addr_t())
+{
return uhd::device::find(dev_addr);
}
%}
-static uhd::device_addrs_t find_devices_raw(const uhd::device_addr_t &dev_addr = uhd::device_addr_t());
+static uhd::device_addrs_t find_devices_raw(
+ const uhd::device_addr_t &dev_addr = uhd::device_addr_t());
////////////////////////////////////////////////////////////////////////
// helpful constants