aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/dboard_manager/x4xx_debug_db.py
blob: f5e023229b7d42d8e6ce54bb102d5ac711ae271c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#
# 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))