aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python')
-rw-r--r--mpm/python/CMakeLists.txt56
-rw-r--r--mpm/python/lib_periphs.cpp49
-rw-r--r--mpm/python/lib_periphs.hpp4
-rw-r--r--mpm/python/n310_periphs.cpp21
-rw-r--r--mpm/python/n310_periphs.hpp3
-rw-r--r--mpm/python/pyusrp_periphs.cpp19
-rwxr-xr-xmpm/python/setup.py.in44
-rwxr-xr-xmpm/python/socket_test.py22
-rwxr-xr-xmpm/python/test_lmk.py7
-rwxr-xr-xmpm/python/test_rpc.py63
-rw-r--r--mpm/python/tests_periphs.cpp18
-rw-r--r--mpm/python/tests_periphs.hpp3
-rwxr-xr-xmpm/python/usrp_hwd.py57
-rw-r--r--mpm/python/usrp_mpm/CMakeLists.txt30
-rw-r--r--mpm/python/usrp_mpm/__init__.py23
-rw-r--r--mpm/python/usrp_mpm/discovery.py76
-rw-r--r--mpm/python/usrp_mpm/periphs.py71
-rw-r--r--mpm/python/usrp_mpm/rpc_process.py48
-rw-r--r--mpm/python/usrp_mpm/rpc_server.py69
-rw-r--r--mpm/python/usrp_mpm/types.py38
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