diff options
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_mboard_impl.cpp | 39 | ||||
-rwxr-xr-x | mpm/python/usrp_hwd.py | 3 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/base.py | 3 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/eiscat.py | 27 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/base.py | 9 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n310.py | 3 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/rpc_server.py | 42 |
7 files changed, 98 insertions, 28 deletions
diff --git a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp index 82967ecad..135d2973e 100644 --- a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp @@ -22,7 +22,12 @@ #include <thread> namespace { - const size_t MPMD_RECLAIM_INTERVAL_MS = 1000; + //! Time between reclaims (ms) + const size_t MPMD_RECLAIM_INTERVAL_MS = 1000; + //! Default timeout value for the init() RPC call (ms) + const size_t MPMD_DEFAULT_INIT_TIMEOUT = 30000; + //! Default timeout value for RPC calls (ms) + const size_t MPMD_DEFAULT_RPC_TIMEOUT = 2000; const std::string MPMD_DEFAULT_SESSION_ID = "UHD"; } @@ -43,12 +48,6 @@ mpmd_mboard_impl::mpmd_mboard_impl( << rpc_server_addr << " mboard args: " << mb_args.to_string() ; - auto device_info_dict = rpc->request<dev_info>("get_device_info"); - for (const auto &info_pair: device_info_dict) { - device_info[info_pair.first] = info_pair.second; - } - UHD_LOGGER_TRACE("MPMD") - << "MPM reports device info: " << device_info.to_string(); // Claim logic auto rpc_token = rpc->request<std::string>("claim", @@ -68,6 +67,32 @@ mpmd_mboard_impl::mpmd_mboard_impl( ); }); + // Init and query info + std::map<std::string, std::string> mpm_device_args; + const std::set<std::string> key_blacklist{ // TODO put this somewhere else + "serial", "claimed", "type", "rev", "addr" + }; + for (const auto &key : mb_args.keys()) { + if (not key_blacklist.count(key)) { + mpm_device_args[key] = mb_args[key]; + } + } + rpc->set_timeout(mb_args.cast<size_t>( + "init_timeout", MPMD_DEFAULT_INIT_TIMEOUT + )); + if (not rpc->request_with_token<bool>("init", mpm_device_args)) { + throw uhd::runtime_error("Failed to initialize device."); + } + auto device_info_dict = rpc->request<dev_info>("get_device_info"); + for (const auto &info_pair : device_info_dict) { + device_info[info_pair.first] = info_pair.second; + } + UHD_LOGGER_TRACE("MPMD") + << "MPM reports device info: " << device_info.to_string(); + rpc->set_timeout(mb_args.cast<size_t>( + "rpc_timeout", MPMD_DEFAULT_RPC_TIMEOUT + )); + // Initialize properties this->num_xbars = rpc->request<size_t>("get_num_xbars"); // Local addresses are not yet valid after this! diff --git a/mpm/python/usrp_hwd.py b/mpm/python/usrp_hwd.py index 27c2870df..8abc89923 100755 --- a/mpm/python/usrp_hwd.py +++ b/mpm/python/usrp_hwd.py @@ -115,8 +115,8 @@ def main(): "type": mgr._get_device_info()["type"], "serial": mgr._get_device_info()["serial"] } - mgr.init(args.default_args) # TODO really this should be called by the UHD session if args.init_only: + mgr.init(args.default_args) log.info("Terminating on user request before launching RPC server.") mgr.deinit() return True @@ -130,7 +130,6 @@ def main(): signal.signal(signal.SIGTERM, kill_time) signal.signal(signal.SIGINT, kill_time) signal.pause() - mgr.deinit() # TODO Really this should be called when a device is unclaimed return True if __name__ == '__main__': diff --git a/mpm/python/usrp_mpm/dboard_manager/base.py b/mpm/python/usrp_mpm/dboard_manager/base.py index 724558445..56655f946 100644 --- a/mpm/python/usrp_mpm/dboard_manager/base.py +++ b/mpm/python/usrp_mpm/dboard_manager/base.py @@ -52,6 +52,7 @@ class DboardManagerBase(object): device_args -- Arbitrary dictionary of info, typically user-defined """ return [] + ### End of overridables ################################################# def __init__(self, slot_idx, **kwargs): self.log = get_logger('dboardManager') @@ -82,7 +83,7 @@ class DboardManagerBase(object): Run the dboard initialization. This typically happens at the beginning of a UHD session. - Must be overridden. + Must be overridden. Must return True/False on success/failure. args -- A dictionary of arbitrary settings that can be used by the dboard code. Similar to device args for UHD. diff --git a/mpm/python/usrp_mpm/dboard_manager/eiscat.py b/mpm/python/usrp_mpm/dboard_manager/eiscat.py index dc4ee1cac..980a64fcc 100644 --- a/mpm/python/usrp_mpm/dboard_manager/eiscat.py +++ b/mpm/python/usrp_mpm/dboard_manager/eiscat.py @@ -17,10 +17,10 @@ """ EISCAT rx board implementation module """ -from builtins import range -from builtins import object import time +from builtins import range +from builtins import object from ..mpmlog import get_logger from ..uio import UIO from . import lib @@ -28,8 +28,6 @@ from .base import DboardManagerBase from .lmk_eiscat import LMK04828EISCAT from usrp_mpm.cores import ClockSynchronizer -N_CHANS = 8 # Chans per dboard - def create_spidev_iface_sane(dev_node): """ Create a regs iface from a spidev node (sane values) @@ -410,6 +408,12 @@ class EISCAT(DboardManagerBase): self.clock_synchronizer = None self._spi_ifaces = None + def is_initialized(self): + """ + Returns True if the daughterboard is a usable state and ready to stream + """ + return self.initialized + def init(self, args): """ Execute necessary actions to bring up the daughterboard: @@ -425,6 +429,9 @@ class EISCAT(DboardManagerBase): For operation (streaming), the ADCs and deframers still need to be initialized. + + Note that this function will do nothing if the device was previously + initialized. """ def _init_dboard_regs(): " Create a UIO object to talk to dboard regs " @@ -493,6 +500,12 @@ class EISCAT(DboardManagerBase): adc.reset() return adcs # Go, go, go! + if self.initialized and not args.get("force_init", False): + self.log.info( + "Dboard was previously initialized; skipping init. " \ + "Specify force_init=1 to force initialization." + ) + return True self.log.info("init() called with args `{}'".format( ",".join(['{}={}'.format(x, args[x]) for x in args]) )) @@ -534,6 +547,7 @@ class EISCAT(DboardManagerBase): self._spi_ifaces['adc0'], self._spi_ifaces['adc1'], )) self.log.trace("ADC Reset Sequence Complete!") + return True def send_sysref(self): @@ -582,12 +596,13 @@ class EISCAT(DboardManagerBase): def shutdown(self): """ - Safely turn off the daughterboard + Safely turn off the daughterboard. This will take away power to the + components; a re-initialization will be necessary after calling this. """ self.log.info("Shutting down daughterboard") + self.initialized = False self._deinit_power(self.radio_regs) - def _init_power(self, regs): """ Turn on power to the dboard. diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py index 89282265f..c0e64ade3 100644 --- a/mpm/python/usrp_mpm/periph_manager/base.py +++ b/mpm/python/usrp_mpm/periph_manager/base.py @@ -302,6 +302,12 @@ class PeriphManagerBase(object): passed to the daughterboard's init calls. For additional features, this needs to be overridden. + The main requirement of this function is, after calling it successfully, + all RFNoC blocks must be reachable via CHDR interfaces (i.e., clocks + need to be on). + + Return False on failure, True on success. + args -- A dictionary of args for initialization. Similar to device args in UHD. """ @@ -312,8 +318,7 @@ class PeriphManagerBase(object): self.log.info("Identifying available network interfaces...") self._init_interfaces() self.log.debug("Initializing dboards...") - for dboard in self.dboards: - dboard.init(args) + return all((dboard.init(args) for dboard in self.dboards)) def deinit(self): """ diff --git a/mpm/python/usrp_mpm/periph_manager/n310.py b/mpm/python/usrp_mpm/periph_manager/n310.py index 7b43aec38..537f43ee8 100644 --- a/mpm/python/usrp_mpm/periph_manager/n310.py +++ b/mpm/python/usrp_mpm/periph_manager/n310.py @@ -141,13 +141,14 @@ class n310(PeriphManagerBase): Calls init() on the parent class, and then programs the Ethernet dispatchers accordingly. """ - super(n310, self).init(args) + result = super(n310, self).init(args) self._eth_dispatchers = { x: EthDispatcherTable(self.eth_tables.get(x)) for x in list(self._chdr_interfaces.keys()) } for ifname, table in iteritems(self._eth_dispatchers): table.set_ipv4_addr(self._chdr_interfaces[ifname]['ip_addr']) + return result def _allocate_sid(self, sender_addr, port, sid, xbar_src_addr, xbar_src_port, new_ep): """ diff --git a/mpm/python/usrp_mpm/rpc_server.py b/mpm/python/usrp_mpm/rpc_server.py index 43843cff5..982e94c91 100644 --- a/mpm/python/usrp_mpm/rpc_server.py +++ b/mpm/python/usrp_mpm/rpc_server.py @@ -153,12 +153,13 @@ class MPMServer(RPCServer): def claim(self, session_id): """ - claim `token` - tries to claim MPM device and provides a human readable session_id - This is a safe method which can be called without a claim on the device + claim `token` - tries to claim MPM device and provides a human readable + session_id. """ self._state.lock.acquire() if self._state.claim_status.value: - return "" + self.log.warning("Someone tried to claim this device again") + raise RuntimeError("Double-claim") self.log.debug( "Claiming from: %s, Session ID: %s", self.client_host, @@ -169,11 +170,34 @@ class MPMServer(RPCServer): ), 'ascii') self._state.claim_status.value = True self._state.lock.release() - self.session_id = session_id + self.session_id = session_id + " ({})".format(self.client_host) self._reset_timer() - self.log.debug("giving token: %s to host: %s", self._state.claim_token.value, self.client_host) + self.log.debug( + "giving token: %s to host: %s", + self._state.claim_token.value, + self.client_host + ) return self._state.claim_token.value + + def init(self, token, args): + """ + Initialize device. See PeriphManagerBase for details. This is forwarded + from here import to give extra control over the claim release timeout. + """ + if not self._check_token_valid(token): + self.log.warning( + "Attempt to init without valid claim from {}".format( + self.client_host + ) + ) + raise RuntimeError("init() called without valid claim.") + self._timer.kill() # Stop the timer, inits can take some time. + result = self.periph_manager.init(args) + self.log.debug("init() result: {}".format(result)) + self._reset_timer() + return result + def reclaim(self, token): """ reclaim a MPM device with a token. This operation will fail @@ -203,8 +227,8 @@ class MPMServer(RPCServer): """ unconditional unclaim - for internal use """ - self.log.debug("Releasing claim on session `{}' by `{}'".format( - self.session_id, self.client_host + self.log.debug("Releasing claim on session `{}'".format( + self.session_id )) self._state.claim_status.value = False self._state.claim_token.value = b'' @@ -213,12 +237,12 @@ class MPMServer(RPCServer): self.periph_manager.deinit() self._timer.kill() - def _reset_timer(self): + def _reset_timer(self, timeout=TIMEOUT_INTERVAL): """ reset unclaim timer """ self._timer.kill() - self._timer = spawn_later(TIMEOUT_INTERVAL, self._unclaim) + self._timer = spawn_later(timeout, self._unclaim) def unclaim(self, token): """ |