# # Copyright 2020 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # """ Debug dboard implementation module """ from usrp_mpm.dboard_manager import DboardManagerBase from usrp_mpm.mpmlog import get_logger from usrp_mpm.sys_utils.gpio import Gpio class DebugDboardSignalPath: def __init__(self, slot_idx, path, adc_indexes, dac_indexes, loopback): self.log = get_logger("X4xxDebugDboard-{}-path-{}".format(slot_idx, path)) self.rxa2_led = Gpio("DB{}_RX{}2_LED".format(slot_idx, path), Gpio.OUTPUT, 0) self.rxa_led = Gpio("DB{}_RX{}_LED".format(slot_idx, path), Gpio.OUTPUT, 0) self.txa_led = Gpio("DB{}_TX{}_LED".format(slot_idx, path), Gpio.OUTPUT, 0) self.trx_ctrl = Gpio("DB{}_TRX{}_CTRL".format(slot_idx, path), Gpio.OUTPUT, 0) self.rx_mux_ctrl = Gpio("DB{}_RX{}_MUX_CTRL".format(slot_idx, path), Gpio.OUTPUT, 0) self.tx_mux_ctrl = Gpio("DB{}_TX{}_MUX_CTRL".format(slot_idx, path), Gpio.OUTPUT, 0) self._adc_indices = adc_indexes self._dac_indices = dac_indexes self._loopback = loopback self._path = path def configure(self, adc, dac, loopback): """ Configure this path with the appropriate settings """ if adc.lower() not in self._adc_indices: error_msg = "Could not find ADC {} on path {}. Possible ADCs: {}".format( adc, self._path, ", ".join(self._adc_indices.keys()) ) self.log.error(error_msg) raise RuntimeError(error_msg) if dac.lower() not in self._dac_indices: error_msg = "Could not find DAC {} on path {}. Possible DACs: {}".format( dac, self._path, ", ".join(self._dac_indices.keys()) ) self.log.error(error_msg) raise RuntimeError(error_msg) self.rx_mux_ctrl.set(self._adc_indices[adc.lower()]) self.tx_mux_ctrl.set(self._dac_indices[dac.lower()]) self.trx_ctrl.set(self._loopback if loopback else not self._loopback) class X4xxDebugDboard(DboardManagerBase): """ Holds all dboard specific information and methods of the X4xx debug dboard """ ######################################################################### # Overridables # # See DboardManagerBase for documentation on these fields ######################################################################### pids = [0x4001] ### End of overridables ################################################# def __init__(self, slot_idx, **kwargs): DboardManagerBase.__init__(self, slot_idx, **kwargs) self.log = get_logger("X4xxDebugDboard-{}".format(slot_idx)) self.log.trace("Initializing X4xxDebug daughterboard, slot index %d", self.slot_idx) # Interface with MB HW if 'db_iface' not in kwargs: self.log.error("Required DB Iface was not provided!") raise RuntimeError("Required DB Iface was not provided!") self.db_iface = kwargs['db_iface'] # Power on the card self.db_iface.enable_daughterboard(enable=True) if not self.db_iface.check_enable_daughterboard(): self.db_iface.enable_daughterboard(enable=False) self.log.error('Debug dboard {} power up failed'.format(self.slot_idx)) raise RuntimeError('Debug dboard {} power up failed'.format(self.slot_idx)) self._paths = { "a": DebugDboardSignalPath( slot_idx, "A", { "adc0": 1, "adc2": 0, }, { "dac0": 1, "dac2": 0, }, 1 # TRXA_CTRL=1 enables loopback ), "b": DebugDboardSignalPath( slot_idx, "B", { "adc3": 1, "adc1": 0, }, { "dac3": 1, "dac1": 0, }, 0 # TRXB_CTRL=0 enables loopback ), } # TODO: Configure the correct RFDC settings for this board #if not self.db_iface.disable_mixer(): # raise RuntimeError("Received an error disabling the mixer for slot_idx={}".format(slot_idx)) def init(self, args): """ Execute necessary init dance to bring up dboard """ self.log.debug("init() called with args `{}'".format( ",".join(['{}={}'.format(x, args[x]) for x in args]) )) self.config_path("a", "adc0", "dac0", 0) self.config_path("b", "adc1", "dac1", 0) return True def deinit(self): pass def tear_down(self): self.db_iface.tear_down() def config_path(self, path, adc, dac, loopback): """ Configure the signal paths on the daughterboard. path - Select between front panel connectors A or B. The two paths are unconnected. adc - Select which ADC to connect to the path (adc0 or adc2 on A, adc1 or adc3 on B) dac - Select which DAC to connect to the path (dac0 or dac2 on A, dac1 or dac3 on B) loopback - Whether to enable loopback (1) or route the ADC/DACs to the front panel (0) Example MPM shell usage: > db_0_config_path a adc0 dac2 1 """ if path.lower() not in self._paths: self.log.error("Tried to configure path {} which does not exist!".format(path)) raise RuntimeError("Tried to configure path {} which does not exist!".format(path)) path = self._paths[path.lower()] path.configure(adc, dac, int(loopback))