aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/simulator
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python/usrp_mpm/simulator')
-rw-r--r--mpm/python/usrp_mpm/simulator/CMakeLists.txt2
-rw-r--r--mpm/python/usrp_mpm/simulator/chdr_endpoint.py3
-rw-r--r--mpm/python/usrp_mpm/simulator/config.py80
-rw-r--r--mpm/python/usrp_mpm/simulator/hardware_presets.py10
-rw-r--r--mpm/python/usrp_mpm/simulator/rfnoc_graph.py6
-rw-r--r--mpm/python/usrp_mpm/simulator/sim_dboard.py34
-rw-r--r--mpm/python/usrp_mpm/simulator/sim_dboard_catalina.py33
7 files changed, 124 insertions, 44 deletions
diff --git a/mpm/python/usrp_mpm/simulator/CMakeLists.txt b/mpm/python/usrp_mpm/simulator/CMakeLists.txt
index 21f281e52..ef3c9bc8c 100644
--- a/mpm/python/usrp_mpm/simulator/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/simulator/CMakeLists.txt
@@ -12,7 +12,7 @@ set(USRP_MPM_FILES ${USRP_MPM_FILES})
set(USRP_MPM_SIMULATOR_FILES
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/sim_dboard.py
- ${CMAKE_CURRENT_SOURCE_DIR}/sim_dboard_catalina.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/hardware_presets.py
${CMAKE_CURRENT_SOURCE_DIR}/chdr_endpoint.py
${CMAKE_CURRENT_SOURCE_DIR}/noc_block_regs.py
${CMAKE_CURRENT_SOURCE_DIR}/rfnoc_graph.py
diff --git a/mpm/python/usrp_mpm/simulator/chdr_endpoint.py b/mpm/python/usrp_mpm/simulator/chdr_endpoint.py
index 17d707ae7..bca7f9c69 100644
--- a/mpm/python/usrp_mpm/simulator/chdr_endpoint.py
+++ b/mpm/python/usrp_mpm/simulator/chdr_endpoint.py
@@ -36,7 +36,8 @@ class ChdrEndpoint:
self.send_queue = SelectableQueue()
self.send_wrapper = SendWrapper(self.send_queue)
- self.graph = RFNoCGraph(self.get_default_nodes(), self.log, 1, self.send_wrapper, CHDR_W)
+ self.graph = RFNoCGraph(self.get_default_nodes(), self.log, 0, self.send_wrapper,
+ CHDR_W, config.hardware.rfnoc_device_type)
self.thread = Thread(target=self.socket_worker, daemon=True)
self.thread.start()
diff --git a/mpm/python/usrp_mpm/simulator/config.py b/mpm/python/usrp_mpm/simulator/config.py
index a5f07950d..6698f9fd0 100644
--- a/mpm/python/usrp_mpm/simulator/config.py
+++ b/mpm/python/usrp_mpm/simulator/config.py
@@ -12,6 +12,47 @@ it identifies itself as.
import configparser
from .sample_source import sinks, sources, NullSamples
+from .hardware_presets import presets
+import numbers
+
+class HardwareDescriptor:
+ """This class contains the various magic numbers that are needed to
+ identify specific hardware to UHD
+ """
+ def __init__(self, product, uhd_device_type, description, pid, serial_num, dboard_class, rfnoc_device_type):
+ """
+ product -> MPM Product, stored in PeriphManager.mboard_info['product']
+ e.g. "e320", "b200"
+ uhd_device_type -> A device_type string recognized by UHD's device discovery.
+ This is the same identifier that goes into --args=type="..."
+ e.g. "e3xx", "n3xx"
+ description -> MPM description, user visible. Stored in PeriphManager.description
+ pid -> motherboard pid, stored as a key in PeriphManager.pids
+ e.g. 0xE320
+ serial_num -> Device Specific serial number.
+ e.g. "3196D2A"
+ dboard_class -> Python class which should be instantiated as a daughterboard
+ rfnoc_device_type -> Device Type read from NoC Core Registers
+ see defaults.hpp:device_type_t
+ e.g. 0xE320, 0xA300
+ """
+ self.product = product
+ self.uhd_device_type = uhd_device_type
+ self.description = description
+ self.pid = pid
+ self.serial_num = serial_num
+ self.dboard_class = dboard_class
+ self.rfnoc_device_type = rfnoc_device_type
+
+ @classmethod
+ def from_dict(cls, dict):
+ return cls(dict['product'],
+ dict['uhd_device_type'],
+ dict['description'],
+ dict['pid'],
+ dict['serial_num'],
+ dict['dboard_class'],
+ dict['rfnoc_device_type'])
class Config:
"""This class represents a configuration file for the usrp simulator.
@@ -24,18 +65,41 @@ class Config:
sample_source.py). The other key value pairs in the section are
passed to the source/sink constructor as strings through **kwargs
"""
- def __init__(self, source_gen, sink_gen):
+ def __init__(self, source_gen, sink_gen, hardware):
self.source_gen = source_gen
self.sink_gen = sink_gen
+ self.hardware = hardware
@classmethod
- def from_path(cls, path):
+ def from_path(cls, log, path):
"""Parse a config .ini file from a path"""
parser = configparser.ConfigParser()
parser.read(path)
- source_gen = Config._read_sample_section(parser['sample.source'], sources)
- sink_gen = Config._read_sample_section(parser['sample.sink'], sinks)
- return cls(source_gen, sink_gen)
+ source_gen = NullSamples
+ # Here we read data from a section and then pop it.
+ # For some reason, you can't iterate over a section (needed to make a dict),
+ # after its been popped.
+ if 'sample.source' in parser:
+ source_gen = Config._read_sample_section(parser['sample.source'], sources)
+ parser.pop('sample.source')
+ sink_gen = NullSamples
+ if 'sample.sink' in parser:
+ sink_gen = Config._read_sample_section(parser['sample.sink'], sinks)
+ parser.pop('sample.sink')
+ hardware_section = dict(parser['hardware'])
+ preset_name = hardware_section.get('preset', None)
+ hardware_preset = presets[preset_name].copy() if preset_name is not None else {}
+ hardware_preset.update(hardware_section)
+ hardware = HardwareDescriptor.from_dict(hardware_preset)
+ parser.pop('hardware')
+ for unused_section in parser:
+ # Python sticks this into all config files
+ if unused_section == 'DEFAULT':
+ continue
+ # This helps stop you from shooting yourself in the foot when you add
+ # the [sampel.sink] section
+ log.warning("Unrecognized section in config file: {}".format(unused_section))
+ return cls(source_gen, sink_gen, hardware)
@staticmethod
def _read_sample_section(section, lookup):
@@ -49,4 +113,8 @@ class Config:
@classmethod
def default(cls):
"""Return a default config"""
- return cls(NullSamples, NullSamples)
+ hardware = dict(presets['E320'])
+ # For the uninitiated, this is how you spell Fake Device in hex
+ hardware['serial_num'] = "FA4EDE7"
+ hardware = HardwareDescriptor.from_dict(hardware)
+ return cls(NullSamples, NullSamples, hardware)
diff --git a/mpm/python/usrp_mpm/simulator/hardware_presets.py b/mpm/python/usrp_mpm/simulator/hardware_presets.py
new file mode 100644
index 000000000..b6747bb88
--- /dev/null
+++ b/mpm/python/usrp_mpm/simulator/hardware_presets.py
@@ -0,0 +1,10 @@
+presets = {}
+
+presets['E320'] = {
+ 'product': "e320",
+ 'uhd_device_type': "e3xx",
+ 'description': "E320-Series Device - SIMULATED",
+ 'pid': 0xE320,
+ 'dboard_class': "SimulatedCatalinaDboard",
+ 'rfnoc_device_type': 0xE320
+}
diff --git a/mpm/python/usrp_mpm/simulator/rfnoc_graph.py b/mpm/python/usrp_mpm/simulator/rfnoc_graph.py
index ada6e70b0..a2b536ed2 100644
--- a/mpm/python/usrp_mpm/simulator/rfnoc_graph.py
+++ b/mpm/python/usrp_mpm/simulator/rfnoc_graph.py
@@ -148,7 +148,7 @@ class RFNoCGraph:
It serves as an interface between the ChdrEndpoint and the
individual blocks/nodes.
"""
- def __init__(self, graph_list, log, device_id, send_wrapper, chdr_w):
+ def __init__(self, graph_list, log, device_id, send_wrapper, chdr_w, rfnoc_device_id):
self.log = log.getChild("Graph")
self.device_id = device_id
self.stream_spec = StreamSpec()
@@ -173,8 +173,8 @@ class RFNoCGraph:
(NocBlockPort(0, 1), StreamEndpointPort(0, 1))
]
self.regs = NocBlockRegs(self.log, 1 << 16, True, 1, [radio], len(self.stream_ep), 1,
- 0xE320, adj_list, 8, 1, self.get_stream_spec, self.radio_tx_cmd,
- self.radio_tx_stop)
+ rfnoc_device_id, adj_list, 8, 1, self.get_stream_spec,
+ self.radio_tx_cmd, self.radio_tx_stop)
def radio_tx_cmd(self, sep_block_id):
"""Triggers the creation of a ChdrOutputStream in the ChdrEndpoint using
diff --git a/mpm/python/usrp_mpm/simulator/sim_dboard.py b/mpm/python/usrp_mpm/simulator/sim_dboard.py
index a264eae9c..90f8be724 100644
--- a/mpm/python/usrp_mpm/simulator/sim_dboard.py
+++ b/mpm/python/usrp_mpm/simulator/sim_dboard.py
@@ -7,6 +7,11 @@ from usrp_mpm.dboard_manager import DboardManagerBase
from usrp_mpm.mpmlog import get_logger
from usrp_mpm.mpmutils import to_native_str
+registry = {}
+
+def register_dboard_class(cls):
+ registry[cls.__name__] = cls
+
class SimulatedDboardBase(DboardManagerBase):
"""
A class to simulate daughterboards in a simulated device.
@@ -57,3 +62,32 @@ class SimulatedDboardBase(DboardManagerBase):
self.log.debug("Called {} with args: {}".format(prop_name, args))
return func(*args)
setattr(self, prop_name, wrapped_func)
+
+class SimulatedCatalinaDboard(SimulatedDboardBase):
+ pids = [0x0110]
+
+ extra_methods = [
+ ("set_gain", lambda target, gain: gain),
+ ("catalina_tune", lambda which, freq: freq),
+ ("set_bw_filter", lambda which, freq: freq),
+ "set_dc_offset_auto",
+ "set_iq_balance_auto",
+ "set_agc",
+ "set_active_chains",
+ "set_timing_mode",
+ "data_port_loopback"
+ ]
+
+ def __init__(self, slot_idx, clock_rate_cb, **kwargs):
+ super().__init__(slot_idx, **kwargs)
+ self.clock_rate_cb = clock_rate_cb
+ self.master_clock_rate = 122.88e6
+
+ def get_master_clock_rate(self):
+ return self.master_clock_rate
+
+ def set_catalina_clock_rate(self, rate):
+ self.clock_rate_cb(rate)
+ return rate
+
+register_dboard_class(SimulatedCatalinaDboard)
diff --git a/mpm/python/usrp_mpm/simulator/sim_dboard_catalina.py b/mpm/python/usrp_mpm/simulator/sim_dboard_catalina.py
deleted file mode 100644
index 4e46d1410..000000000
--- a/mpm/python/usrp_mpm/simulator/sim_dboard_catalina.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Copyright 2020 Ettus Research, a National Instruments Brand
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-from .sim_dboard import SimulatedDboardBase
-
-class SimulatedCatalinaDboard(SimulatedDboardBase):
- pids = [0x0110]
-
- extra_methods = [
- ("set_gain", lambda target, gain: gain),
- ("catalina_tune", lambda which, freq: freq),
- ("set_bw_filter", lambda which, freq: freq),
- "set_dc_offset_auto",
- "set_iq_balance_auto",
- "set_agc",
- "set_active_chains",
- "set_timing_mode",
- "data_port_loopback"
- ]
-
- def __init__(self, slot_idx, clock_rate_cb, **kwargs):
- super().__init__(slot_idx, **kwargs)
- self.clock_rate_cb = clock_rate_cb
- self.master_clock_rate = 122.88e6
-
- def get_master_clock_rate(self):
- return self.master_clock_rate
-
- def set_catalina_clock_rate(self, rate):
- self.clock_rate_cb(rate)
- return rate