diff options
Diffstat (limited to 'mpm/python')
-rw-r--r-- | mpm/python/CMakeLists.txt | 56 | ||||
-rw-r--r-- | mpm/python/lib_periphs.cpp | 49 | ||||
-rw-r--r-- | mpm/python/lib_periphs.hpp | 4 | ||||
-rw-r--r-- | mpm/python/n310_periphs.cpp | 21 | ||||
-rw-r--r-- | mpm/python/n310_periphs.hpp | 3 | ||||
-rw-r--r-- | mpm/python/pyusrp_periphs.cpp | 19 | ||||
-rwxr-xr-x | mpm/python/setup.py.in | 44 | ||||
-rwxr-xr-x | mpm/python/socket_test.py | 22 | ||||
-rwxr-xr-x | mpm/python/test_lmk.py | 7 | ||||
-rwxr-xr-x | mpm/python/test_rpc.py | 63 | ||||
-rw-r--r-- | mpm/python/tests_periphs.cpp | 18 | ||||
-rw-r--r-- | mpm/python/tests_periphs.hpp | 3 | ||||
-rwxr-xr-x | mpm/python/usrp_hwd.py | 57 | ||||
-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 |
20 files changed, 721 insertions, 0 deletions
diff --git a/mpm/python/CMakeLists.txt b/mpm/python/CMakeLists.txt new file mode 100644 index 000000000..7d3b251d7 --- /dev/null +++ b/mpm/python/CMakeLists.txt @@ -0,0 +1,56 @@ +# +# 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(UHD_HOST_ROOT ${CMAKE_SOURCE_DIR}/../host) +LIST(APPEND + pyusrp_periphs_sources + pyusrp_periphs.cpp + lib_periphs.cpp + n310_periphs.cpp + # tests_periphs.cpp + ) + +ADD_LIBRARY(pyusrp_periphs SHARED ${pyusrp_periphs_sources}) +TARGET_INCLUDE_DIRECTORIES(pyusrp_periphs PUBLIC ${PYTHON_INCLUDE_DIRS} ${UHD_HOST_ROOT}/lib/usrp/common) +TARGET_LINK_LIBRARIES(pyusrp_periphs ${Boost_PYTHON_LIBRARY} ${Boost_LIBRARIES} usrp-periphs) +ADD_CUSTOM_COMMAND(TARGET pyusrp_periphs POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/libpyusrp_periphs.so ${CMAKE_CURRENT_BINARY_DIR}/usrp_mpm/libpyusrp_periphs.so) + +ADD_SUBDIRECTORY(usrp_mpm) + +SET(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") +SET(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py") +SET(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") + +CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY}) + +ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT} + COMMAND ${CMAKE_COMMAND} -E copy ${USRP_MPM_FILES} ${CMAKE_CURRENT_BINARY_DIR}/usrp_mpm + COMMAND ${PYTHON} ${SETUP_PY} -q build + COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT} + DEPENDS ${USRP_MPM_FILES}) +ADD_CUSTOM_TARGET(usrp_mpm ALL DEPENDS ${OUTPUT} pyusrp_periphs) + +EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c + "from distutils import sysconfig; print sysconfig.get_python_lib(plat_specific=True, prefix='')" + OUTPUT_VARIABLE USRP_MPM_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE +) +INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/lib/usrp_mpm DESTINATION ${CMAKE_INSTALL_PREFIX}/${USRP_MPM_PYTHON_DIR}) diff --git a/mpm/python/lib_periphs.cpp b/mpm/python/lib_periphs.cpp new file mode 100644 index 000000000..030752ede --- /dev/null +++ b/mpm/python/lib_periphs.cpp @@ -0,0 +1,49 @@ +#include "lib_periphs.hpp" +#include "lmk04828.hpp" +#include <mpm/spi_iface.hpp> +#include <boost/python.hpp> + +namespace bp = boost::python; + +void export_lmk(){ + //Register submodule types + bp::object lmk_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs.lmk")))); + bp::scope().attr("lmk") = lmk_module; + bp::scope io_scope = lmk_module; + + bp::class_<lmk04828_iface, boost::shared_ptr<lmk04828_iface>, boost::noncopyable >("lmk04828_iface", bp::no_init) + .def("make", &lmk04828_iface::make) + .def("verify_chip_id", &lmk04828_iface::verify_chip_id) + .def("init", &lmk04828_iface::init) + .def("send_sysref_pulse", &lmk04828_iface::send_sysref_pulse) + ; +} + +void export_spi(){ + //Register submodule types + bp::object spi_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs.spi")))); + bp::scope().attr("spi") = spi_module; + bp::scope io_scope = spi_module; + + bp::class_<mpm::spi_iface, boost::noncopyable>("spi_iface", bp::no_init) + .def("write_byte", &mpm::spi_iface::write_byte) + .def("write_bytes", &mpm::spi_iface::write_bytes) + .def("read_byte", &mpm::spi_iface::read_byte) + .def("write_field", &mpm::spi_iface::write_field) + .def("read_field", &mpm::spi_iface::read_field) + .def("get_wire_mode", &mpm::spi_iface::get_wire_mode) + .def("get_endianness", &mpm::spi_iface::get_endianness) + .def("get_chip_select", &mpm::spi_iface::get_chip_select) + ; + + bp::enum_<mpm::spi_iface::spi_endianness_t>("spi_endianness") + .value("lsb_first", mpm::spi_iface::spi_endianness_t::LSB_FIRST) + .value("msb_first", mpm::spi_iface::spi_endianness_t::MSB_FIRST) + ; + + bp::enum_<mpm::spi_iface::spi_wire_mode_t>("spi_wire_mode") + .value("three_wire_mode", mpm::spi_iface::spi_wire_mode_t::THREE_WIRE_MODE) + .value("four_wire_mode", mpm::spi_iface::spi_wire_mode_t::FOUR_WIRE_MODE) + ; +} + diff --git a/mpm/python/lib_periphs.hpp b/mpm/python/lib_periphs.hpp new file mode 100644 index 000000000..2ea023c5c --- /dev/null +++ b/mpm/python/lib_periphs.hpp @@ -0,0 +1,4 @@ +#pragma once + +void export_lmk(); +void export_spi(); diff --git a/mpm/python/n310_periphs.cpp b/mpm/python/n310_periphs.cpp new file mode 100644 index 000000000..42fea61b1 --- /dev/null +++ b/mpm/python/n310_periphs.cpp @@ -0,0 +1,21 @@ +#include "n310_periphs.hpp" +#include "../n310/periph_manager.hpp" +#include <boost/python.hpp> +#include <memory> + +namespace bp = boost::python; + +void export_n3xx(){ + //Register submodule types + bp::object n3xx_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs.n3xx")))); + bp::scope().attr("n3xx") = n3xx_module; + bp::scope io_scope = n3xx_module; + + bp::class_<mpm::n3xx::n3xx_dboard_periph_manager, boost::noncopyable>("dboard_periph_manager", bp::no_init) + .def("get_clock_gen()", &mpm::n3xx::n3xx_dboard_periph_manager::get_clock_gen) + ; + bp::class_<mpm::n3xx::periph_manager, boost::noncopyable, std::shared_ptr<mpm::n3xx::periph_manager> >("periph_manager", bp::init<std::string>()) + .def("get_dboard_A", &mpm::n3xx::periph_manager::get_dboard_A) + ; +} + diff --git a/mpm/python/n310_periphs.hpp b/mpm/python/n310_periphs.hpp new file mode 100644 index 000000000..b4e418947 --- /dev/null +++ b/mpm/python/n310_periphs.hpp @@ -0,0 +1,3 @@ +#pragma once + +void export_n3xx(); diff --git a/mpm/python/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs.cpp new file mode 100644 index 000000000..5a49398c4 --- /dev/null +++ b/mpm/python/pyusrp_periphs.cpp @@ -0,0 +1,19 @@ +#include "n310_periphs.hpp" +// #include "tests_periphs.hpp" +#include "lib_periphs.hpp" +#include <mpm/print_foo.hpp> +#include <boost/python.hpp> +#include <boost/noncopyable.hpp> + +namespace bp = boost::python; + +BOOST_PYTHON_MODULE(libpyusrp_periphs) +{ + bp::object package = bp::scope(); + package.attr("__path__") = "libpyusrp_periphs"; + bp::def("print_foo", &mpm::print_foo); + export_spi(); + // export_tests(); + export_lmk(); + export_n3xx(); +} diff --git a/mpm/python/setup.py.in b/mpm/python/setup.py.in new file mode 100755 index 000000000..ad41eb480 --- /dev/null +++ b/mpm/python/setup.py.in @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# +# 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/>. +# + + + +from setuptools import setup + +setup(name='usrp_mpm', + version='', + description='Universal Software Radio Peripheral (USRP) Machiavellian Puppet Master (MPM) Python API', + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Programming Language :: C++', + 'Programming Language :: Python', + 'Topic :: System :: Hardware :: Hardware Drivers', + ], + keywords='SDR UHD USRP SDR', + author='Ettus Research', + author_email='packages@ettus.com', + url='https://www.ettus.com/', + license='GPLv3', + package_dir={ '': '${CMAKE_CURRENT_BINARY_DIR}' }, + package_data={"usrp_mpm": ["*.so"]}, + zip_safe=False, + packages=['usrp_mpm'], + install_requires=[ + 'numpy' + ]) diff --git a/mpm/python/socket_test.py b/mpm/python/socket_test.py new file mode 100755 index 000000000..1799d2010 --- /dev/null +++ b/mpm/python/socket_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +import socket +import binascii + +UDP_IP = "0.0.0.0" +UDP_PORT = 5000 + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.bind(((UDP_IP, UDP_PORT))) + +send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + +while True: + buf = bytearray(4096) + nbytes, sender = sock.recvfrom_into(buf, 4096) + print(sender) + print("number of bytes: {}".format(nbytes)) + print("received bytes: {}".format(binascii.b2a_hex(buf[:nbytes]))) + + send_sock.sendto(buf[:nbytes], sender) diff --git a/mpm/python/test_lmk.py b/mpm/python/test_lmk.py new file mode 100755 index 000000000..5534bf381 --- /dev/null +++ b/mpm/python/test_lmk.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +import libpyusrp_periphs as p + +dev = p.n3xx.periph_manager("/dev/spidev1.0") +lmk = dev.get_clock_gen() +lmk.verify_chip_id() diff --git a/mpm/python/test_rpc.py b/mpm/python/test_rpc.py new file mode 100755 index 000000000..1a97a103c --- /dev/null +++ b/mpm/python/test_rpc.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +import socket +from mprpc import RPCClient +import usrp_mpm as mpm +import argparse + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("-a", "--address", default="0.0.0.0", type=str, help="Destination address") + parser.add_argument("-p", "--port", default=0, type=int, help="Destination port") + sub_parsers = parser.add_subparsers(dest="command") + + rpc_parser = sub_parsers.add_parser("rpc", help="Issue RPC") + rpc_parser.add_argument("-c", "--call", required=True, help="command to issue") + rpc_parser.add_argument("arguments", nargs="*") + + disc_parser = sub_parsers.add_parser("disc", help="Issue discovery") + return parser.parse_args() + + +def rpc(address, port, command, *args): + if not port: + port = mpm.types.MPM_RPC_PORT + client = RPCClient(address, port) + if args: + result = client.call(command, *args) + else: + result = client.call(command) + return result + + +def discovery(address, port): + if not port: + port = mpm.types.MPM_DISCOVERY_PORT + sock = socket.socket( + socket.AF_INET, + socket.SOCK_DGRAM) + sock.sendto(mpm.types.MPM_DISCOVERY_MESSAGE, (address, port)) + sock.settimeout(1.0) # wait max 1 second + while True: + try: + data, sender = sock.recvfrom(4096) + print("Received respons from: {}".format(sender[0])) + print("Dicovery data: {}".format(data)) + except: + break + + +def main(): + args = parse_args() + if args.command == "rpc": + if args.arguments: + result = rpc(args.address, args.port, args.call, *args.arguments) + else: + result = rpc(args.address, args.port, args.call) + print(result) + elif args.command == "disc": + discovery(args.address, args.port) + + +if __name__ == "__main__": + exit(not(main())) diff --git a/mpm/python/tests_periphs.cpp b/mpm/python/tests_periphs.cpp new file mode 100644 index 000000000..15c1b08b6 --- /dev/null +++ b/mpm/python/tests_periphs.cpp @@ -0,0 +1,18 @@ +#include "tests_periphs.hpp" +#include <mpm/tests/tests_spi_iface.hpp> +#include <mpm/spi_iface.hpp> +#include <boost/python.hpp> + +namespace bp = boost::python; + +void export_tests(){ + //Register submodule types + bp::object tests_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs.tests")))); + bp::scope().attr("tests") = tests_module; + bp::scope io_scope = tests_module; + + bp::class_<mpm::tests_spi_iface, bp::bases<mpm::spi_iface>, std::shared_ptr<mpm::tests_spi_iface> >("test_spi_iface", bp::init<>()) + .def("make", &mpm::tests_spi_iface::make) + .staticmethod("make") + ; +} diff --git a/mpm/python/tests_periphs.hpp b/mpm/python/tests_periphs.hpp new file mode 100644 index 000000000..4b978269d --- /dev/null +++ b/mpm/python/tests_periphs.hpp @@ -0,0 +1,3 @@ +#pragma once + +void export_tests(); diff --git a/mpm/python/usrp_hwd.py b/mpm/python/usrp_hwd.py new file mode 100755 index 000000000..dc72ce3b9 --- /dev/null +++ b/mpm/python/usrp_hwd.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" +Main executable for the USRP Hardware Daemon +""" + +from __future__ import print_function +from multiprocessing import Value +import ctypes +import signal +import time +import usrp_mpm as mpm +from usrp_mpm.types import shared_state +from usrp_mpm.types import graceful_exit + + +def signal_handler(signum, frame): + raise graceful_exit() + + +def main(): + """ + Go, go, go! + + Main process loop. + """ + procs = [] + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGINT, signal_handler) + shared = shared_state() + procs.append(mpm.spawn_discovery_process({'a': "foo"}, shared)) + # procs.append(mpm.spawn_rpc_process("Echo", 5000)) + procs.append(mpm.spawn_rpc_process("MPM", mpm.types.MPM_RPC_PORT, shared)) + try: + for proc in procs: + proc.join() + except mpm.types.graceful_exit: + pass + +if __name__ == '__main__': + exit(not main()) + 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 |