diff options
author | Martin Braun <martin.braun@ettus.com> | 2017-03-08 09:28:55 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:03:44 -0800 |
commit | 1a4348038d0eb57d53475074dca49e8192aeb2d7 (patch) | |
tree | 04c8e87fa9c95d2702aac410f6fb271461acb9bb /mpm/python/usrp_mpm | |
parent | fc8cd827f6b16b9c8c354a216889e6a9d7f37456 (diff) | |
download | uhd-1a4348038d0eb57d53475074dca49e8192aeb2d7.tar.gz uhd-1a4348038d0eb57d53475074dca49e8192aeb2d7.tar.bz2 uhd-1a4348038d0eb57d53475074dca49e8192aeb2d7.zip |
Initial commit for N3xx development.
- Creates mpm/ subdirectory
- First pass at hardware daemon/MPM
- New code for LMK04828, AD9371
- spidev integration
Contributions by:
Martin Braun <martin.braun@ettus.com>
Derek Kozel <derek.kozel@ettus.com>
Mark Meserve <mark.meserve@ni.com>
Andrej Rode <andrej.rode@ettus.com>
Diffstat (limited to 'mpm/python/usrp_mpm')
-rw-r--r-- | mpm/python/usrp_mpm/CMakeLists.txt | 30 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/__init__.py | 23 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/discovery.py | 76 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periphs.py | 71 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/rpc_process.py | 48 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/rpc_server.py | 69 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/types.py | 38 |
7 files changed, 355 insertions, 0 deletions
diff --git a/mpm/python/usrp_mpm/CMakeLists.txt b/mpm/python/usrp_mpm/CMakeLists.txt new file mode 100644 index 000000000..ad3ce41fd --- /dev/null +++ b/mpm/python/usrp_mpm/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# This file included, use CMake directory variables +######################################################################## + +SET(USRP_MPM_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/types.py + ${CMAKE_CURRENT_SOURCE_DIR}/discovery.py + ${CMAKE_CURRENT_SOURCE_DIR}/rpc_process.py + ${CMAKE_CURRENT_SOURCE_DIR}/rpc_server.py + ${CMAKE_CURRENT_SOURCE_DIR}/periphs.py + PARENT_SCOPE + ) diff --git a/mpm/python/usrp_mpm/__init__.py b/mpm/python/usrp_mpm/__init__.py new file mode 100644 index 000000000..dafb6940c --- /dev/null +++ b/mpm/python/usrp_mpm/__init__.py @@ -0,0 +1,23 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" +MPM Module +""" + +from discovery import spawn_discovery_process +from rpc_process import spawn_rpc_process +import types diff --git a/mpm/python/usrp_mpm/discovery.py b/mpm/python/usrp_mpm/discovery.py new file mode 100644 index 000000000..727fe2b94 --- /dev/null +++ b/mpm/python/usrp_mpm/discovery.py @@ -0,0 +1,76 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" +Code to run the discovery port +""" + +from __future__ import print_function +import time +import ctypes +from multiprocessing import Process, Value +from six import iteritems +import socket +from types import MPM_DISCOVERY_PORT, graceful_exit + +RESPONSE_PREAMBLE = "USRP-MPM" +RESPONSE_SEP = ";" +RESPONSE_CLAIMED_KEY = "claimed" + + + +def spawn_discovery_process(device_info, shared_state): + """ + Returns a process that contains the device discovery. + + Arguments: + device_info -- A dictionary of type string -> string. All of these items + will be included in the response string. + """ + # claim_status = Value(ctypes.c_bool, False) + p = Process(target=_discovery_process, args=(device_info, shared_state)) + p.start() + return p + + +def _discovery_process(device_info, state): + """ + The actual process for device discovery. Is spawned by + spawn_discovery_process(). + """ + def create_response_string(): + " Generate the string that gets sent back to the requester. " + return RESPONSE_SEP.join( + [RESPONSE_PREAMBLE] + \ + ["{k}={v}".format(k=k, v=v) for k, v in iteritems(device_info)] + \ + ["{k}={v}".format(k=RESPONSE_CLAIMED_KEY, v=state.claim_status.value)] + \ + ["{k}={v}".format(k="token", v=state.claim_token.value)] + ) + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.bind((("0.0.0.0", MPM_DISCOVERY_PORT))) + + send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + try: + while True: + data, sender = sock.recvfrom(4096) + if data == "MPM-DISC": + send_data = create_response_string() + send_sock.sendto(send_data, sender) + except graceful_exit: + sock.close() + print("I'm done") diff --git a/mpm/python/usrp_mpm/periphs.py b/mpm/python/usrp_mpm/periphs.py new file mode 100644 index 000000000..3a78f224b --- /dev/null +++ b/mpm/python/usrp_mpm/periphs.py @@ -0,0 +1,71 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" + Module +""" + +import libpyusrp_periphs as lib +import re +import logging +log = logging.Logger("usrp_mpm.periphs") + + +def init_periph_manager(mb_type=None, db_types={}, fpga=None): + # Detect motherboard type if not already specified + if mb_type is None: + mb_files = lib.helper.find_mb_file() + with open(mb_files, "r") as f: + info = "".join(f.readlines()) + device_type = re.match("^.*USRP;([-\w])+;.*", info) + if device_type is None: + log.fatal("Could not determine device type from {}".format(info)) + exit(1) + mb_type = device_type.group(1) + # Check if we have an implementation for this motherboard type + try: + device_class = getattr(lib, mb_type) + except AttributeError: + log.fatal("Motherboard class implementation for {} device not found!".format(mb_type)) + exit(1) + + # Detect daughterboard type if not already specified + if not db_types: + db_files = lib.helper.find_db_files() + db_types = {} + for db in db_files: + with open(db, "r") as f: + info = "".join(f.readlines()) + device_type = re.match("^.*SLOT;([\w]);DB;([-\w])+;.*", info) + if device_type is None: + log.fatal("Could not determine device type from: {}".format(info)) + exit(2) + slot = device_type.group(1) + db_type = device_type.group(2) + db_types.update({slot: db_type}) + # Check if we have an implementation for the daughterboard types + for db in db_types.values(): + try: + getattr(lib.db, db) + except AttributeError: + log.fatal("Daughterboard class implementation for {} device not found!".format(db)) + exit(1) + + # Next steps + # + # 1. Load FPGA image + # 2. Use motherboard and daughterboard types to load the FPGA image + # 3. Create periph_manager object wth given mb_type + db_types information diff --git a/mpm/python/usrp_mpm/rpc_process.py b/mpm/python/usrp_mpm/rpc_process.py new file mode 100644 index 000000000..b8783f325 --- /dev/null +++ b/mpm/python/usrp_mpm/rpc_process.py @@ -0,0 +1,48 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" +Code to run the discovery port +""" + +from __future__ import print_function +from multiprocessing import Process + +from gevent.server import StreamServer +from mprpc import RPCServer +from types import graceful_exit, MPM_RPC_PORT +import rpc_server + + + +def spawn_rpc_process(server, state, udp_port=MPM_RPC_PORT): + """ + Returns a process that contains the RPC server + """ + + p_args = [server, udp_port, state] + p = Process(target=_rpc_server_process, args=p_args) + p.start() + return p + + +def _rpc_server_process(server, shared_state, port): + try: + rpc_class = getattr(rpc_server, server+"Server") + server = StreamServer(('0.0.0.0', port), handle=rpc_class(shared_state)) + server.serve_forever() + except graceful_exit: + server.close() diff --git a/mpm/python/usrp_mpm/rpc_server.py b/mpm/python/usrp_mpm/rpc_server.py new file mode 100644 index 000000000..b092abdf7 --- /dev/null +++ b/mpm/python/usrp_mpm/rpc_server.py @@ -0,0 +1,69 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" +Implemented RPC Servers +""" + +from __future__ import print_function +from mprpc import RPCServer +from usrp_mpm import periphs + + +class EchoServer(RPCServer): + def echo(self, arg): + print(arg) + return arg + + +class ClaimServer(RPCServer): + def __init__(self, state): + self._state = state + super(ClaimServer, self).__init__() + + def claim(self, token): + 'claim `token` - claims the MPM device with given token' + if self._state.claim_status.value: + if self._state.claim_token.value == token: + return True + return False + self._state.claim_status.value = True + self._state.claim_token.value = token + return True + + def unclaim(self, token): + 'unclaim `token` - unclaims the MPM device if it is claimed with this token' + if self._state.claim_status.value and self._state.claim_token.value == token: + self._state.claim_status.value = False + self._state.claim_token.value = "" + return True + return False + + def list_methods(self): + methods = filter(lambda entry: not entry.startswith('_'), dir(self)) # Return public methods + methods_with_docs = map(lambda m: (m, getattr(self,m).__doc__), methods) + return methods_with_docs + + +class MPMServer(RPCServer): + def __init__(self, state): + # Instead do self.mboard = periphs.init_periph_manager(args...) + self.mboard = periphs.lib.n3xx.periph_manager("/dev/spidev1.0", "") + + def get_clock_id(self, dboard): + dboard = getattr(self.mboard, "get_dboard_"+dboard) + clk = dboard.get_clock_gen() + return clk.get_chip_id() diff --git a/mpm/python/usrp_mpm/types.py b/mpm/python/usrp_mpm/types.py new file mode 100644 index 000000000..bd7a874a8 --- /dev/null +++ b/mpm/python/usrp_mpm/types.py @@ -0,0 +1,38 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +""" +MPM types +""" +from multiprocessing import Value +from multiprocessing import Array +from multiprocessing import Lock +import ctypes + +MPM_RPC_PORT = 49601 +MPM_DISCOVERY_PORT = 49600 + +MPM_DISCOVERY_MESSAGE = "MPM-DISC" + +class graceful_exit(Exception): + pass + + +class shared_state: + def __init__(self): + self.lock = Lock() + self.claim_status = Value(ctypes.c_bool, False, lock=self.lock) # lock + self.claim_token = Array(ctypes.c_char, 32, lock=self.lock) # String with max length of 32 |