diff options
author | Andrej Rode <andrej.rode@ettus.com> | 2017-03-27 17:07:44 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:03:44 -0800 |
commit | 8ac9014d5c30836665378d2d088b5c602162f8ac (patch) | |
tree | 21708ce88f72da4818e73afe054b89e7f1589fdd | |
parent | 6d332e5ca4a7311406ac285f827c31c9e5b94280 (diff) | |
download | uhd-8ac9014d5c30836665378d2d088b5c602162f8ac.tar.gz uhd-8ac9014d5c30836665378d2d088b5c602162f8ac.tar.bz2 uhd-8ac9014d5c30836665378d2d088b5c602162f8ac.zip |
mpm: CMake cleanup, Python code enhancements
- Send user defined data in ping
- Improve rpc_shell, add mpm_debug.py, fix tracebacks in multiprocessing
26 files changed, 487 insertions, 148 deletions
diff --git a/mpm/CMakeLists.txt b/mpm/CMakeLists.txt index 0de4ad262..65d01b114 100644 --- a/mpm/CMakeLists.txt +++ b/mpm/CMakeLists.txt @@ -61,7 +61,6 @@ FIND_PACKAGE(Boost 1.53 COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) -message("python executable: ${PYTHON_EXECUTABLE}") MESSAGE(STATUS "Boost include directories: ${Boost_INCLUDE_DIRS}") MESSAGE(STATUS "Boost library directories: ${Boost_LIBRARY_DIRS}") @@ -72,19 +71,39 @@ MESSAGE(STATUS "Boost libraries: ${Boost_LIBRARIES}") ######################################################################## SET(PYTHON_ADDITIONAL_VERSIONS 2.7 3.4 3.5) -message("python executable: ${PYTHON_EXECUTABLE}") FIND_PACKAGE(PythonInterp) -message("python executable: ${PYTHON_EXECUTABLE}") FIND_PACKAGE(PythonLibs) -message("python executable: ${PYTHON_EXECUTABLE}") + +######################################################################## +# Install Dirs +######################################################################## +#when the library suffix should be 64 (applies to redhat linux family) +IF(NOT DEFINED LIB_SUFFIX AND REDHAT AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$") + SET(LIB_SUFFIX 64) +ENDIF() +IF(CMAKE_INSTALL_LIBDIR MATCHES lib64) + SET(LIB_SUFFIX 64) +ENDIF() + +SET(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix") +SET(RUNTIME_DIR bin) +SET(LIBRARY_DIR lib${LIB_SUFFIX}) +SET(INCLUDE_DIR include) +SET(PKG_DATA_DIR share/mpm) +IF(NOT DEFINED PKG_LIB_DIR) + SET(PKG_LIB_DIR ${LIBRARY_DIR}/mpm) +ENDIF() +SET(PKG_DOC_DIR share/doc/mpm) +SET(PKG_MAN_DIR share/man/man1) + ######################################################################## # Setup library configuration ######################################################################## SET(CMAKE_CXX_STANDARD 11) -# SET(MPM_DEVICE "tests" CACHE STRING "Choose a MPM device to build") -# SET_PROPERTY(CACHE MPM_DEVICE PROPERTY STRINGS tests) +SET(MPM_DEVICE "n310" CACHE STRING "Choose an MPM device to build") +SET_PROPERTY(CACHE MPM_DEVICE PROPERTY STRINGS n310 tests) SET(UHD_HOST_ROOT ${CMAKE_SOURCE_DIR}/../host) @@ -97,11 +116,6 @@ INCLUDE_DIRECTORIES( ADD_SUBDIRECTORY(dboards) ADD_SUBDIRECTORY(lib) -IF(MPM_DEVICE STREQUAL tests) - ADD_SUBDIRECTORY(tests) -ELSEIF(MPM_DEVICE STREQUAL n310) - ADD_SUBDIRECTORY(n310) -ENDIF(MPM_DEVICE STREQUAL tests) MESSAGE("usrp_periphs objects: ${usrp_periphs_objects}") ADD_LIBRARY(usrp-periphs SHARED ${usrp_periphs_objects}) @@ -111,3 +125,4 @@ TARGET_LINK_LIBRARIES(usrp-periphs ) ADD_SUBDIRECTORY(python) +ADD_SUBDIRECTORY(tools) diff --git a/mpm/include/mpm/CMakeLists.txt b/mpm/include/mpm/CMakeLists.txt index 348073920..47fd2b2ed 100644 --- a/mpm/include/mpm/CMakeLists.txt +++ b/mpm/include/mpm/CMakeLists.txt @@ -16,8 +16,11 @@ # INSTALL(FILES net_helper.hpp - spi_iface.hpp udev_helper.hpp xbar_iface.hpp DESTINATION ${INCLUDE_DIR}/mpm ) +ADD_SUBDIRECTORY(dboards) +ADD_SUBDIRECTORY(lmk04828) +ADD_SUBDIRECTORY(mykonos) +ADD_SUBDIRECTORY(spi) diff --git a/mpm/include/mpm/dboards/CMakeLists.txt b/mpm/include/mpm/dboards/CMakeLists.txt new file mode 100644 index 000000000..b2be87dd7 --- /dev/null +++ b/mpm/include/mpm/dboards/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# 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/>. +# +INSTALL(FILES + magnesium_manager.hpp + DESTINATION ${INCLUDE_DIR}/mpm/dboards +) diff --git a/mpm/include/mpm/lmk04828/CMakeLists.txt b/mpm/include/mpm/lmk04828/CMakeLists.txt new file mode 100644 index 000000000..35df8d624 --- /dev/null +++ b/mpm/include/mpm/lmk04828/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# 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/>. +# +INSTALL(FILES + lmk04828_spi_iface.hpp + DESTINATION ${INCLUDE_DIR}/mpm/lmk04828 +) diff --git a/mpm/include/mpm/mykonos/CMakeLists.txt b/mpm/include/mpm/mykonos/CMakeLists.txt new file mode 100644 index 000000000..3fe8d1419 --- /dev/null +++ b/mpm/include/mpm/mykonos/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# 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/>. +# +INSTALL(FILES + ad937x_ctrl.hpp + DESTINATION ${INCLUDE_DIR}/mpm/mykonos +) diff --git a/mpm/include/mpm/spi/CMakeLists.txt b/mpm/include/mpm/spi/CMakeLists.txt new file mode 100644 index 000000000..f334678d1 --- /dev/null +++ b/mpm/include/mpm/spi/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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/>. +# +INSTALL(FILES + adi_ctrl.hpp + mock_spi.h + spidev_iface.hpp + spi_iface.hpp + spi_lock.hpp + DESTINATION ${INCLUDE_DIR}/mpm/spi +) diff --git a/mpm/python/CMakeLists.txt b/mpm/python/CMakeLists.txt index 382f244c9..7daa3bbf5 100644 --- a/mpm/python/CMakeLists.txt +++ b/mpm/python/CMakeLists.txt @@ -73,17 +73,21 @@ TARGET_INCLUDE_DIRECTORIES(pyusrp_periphs PUBLIC 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) +SET(USRP_MPM_FILES "") ADD_SUBDIRECTORY(usrp_mpm) +SET(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") 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") +SET(PERIPH_MGR_INIT_IN "${CMAKE_CURRENT_SOURCE_DIR}/usrp_mpm/periph_manager/__init__.py.in") +SET(PERIPH_MGR_INIT "${CMAKE_CURRENT_BINARY_DIR}/usrp_mpm/periph_manager/__init__.py") CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY}) +CONFIGURE_FILE(${PERIPH_MGR_INIT_IN} ${PERIPH_MGR_INIT}) ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT} - COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" -DBINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/copy_python_module.cmake - COMMAND ${PYTHON} ${SETUP_PY} -q build + COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" -DBINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/copy_python_module.cmake + COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} -q build COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT} DEPENDS ${USRP_MPM_FILES}) ADD_CUSTOM_TARGET(usrp_mpm ALL DEPENDS ${OUTPUT} pyusrp_periphs) @@ -93,3 +97,6 @@ EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c 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}) +INSTALL(PROGRAMS + usrp_hwd.py + DESTINATION ${RUNTIME_DIR}) diff --git a/mpm/python/copy_python_module.cmake b/mpm/python/copy_python_module.cmake index 1b36d4fab..501793419 100644 --- a/mpm/python/copy_python_module.cmake +++ b/mpm/python/copy_python_module.cmake @@ -1,4 +1,4 @@ SET(BINARY_DIR "" CACHE STRING "") SET(SOURCE_DIR "" CACHE STRING "") -FILE(COPY ${SOURCE_DIR}/usrp_mpm/ DESTINATION ${BINARY_DIR}/usrp_mpm +FILE(COPY "${SOURCE_DIR}/usrp_mpm/" DESTINATION ${BINARY_DIR}/usrp_mpm FILES_MATCHING PATTERN *.py) diff --git a/mpm/python/usrp_hwd.py b/mpm/python/usrp_hwd.py index dc72ce3b9..a0c66f62b 100755 --- a/mpm/python/usrp_hwd.py +++ b/mpm/python/usrp_hwd.py @@ -18,19 +18,33 @@ """ Main executable for the USRP Hardware Daemon """ - from __future__ import print_function -from multiprocessing import Value -import ctypes +from logging import getLogger +from logging import StreamHandler +from logging import DEBUG +from logging import Formatter import signal -import time +import sys import usrp_mpm as mpm from usrp_mpm.types import shared_state -from usrp_mpm.types import graceful_exit +from usrp_mpm.periph_manager import periph_manager + +log = getLogger("usrp_mpm") +_PROCESSES = [] -def signal_handler(signum, frame): - raise graceful_exit() +def kill_time(signal, frame): + """ + kill all processes + to be used in a signal handler + """ + for proc in _PROCESSES: + proc.terminate() + log.info("Terminating pid: {0}".format(proc.pid)) + for proc in _PROCESSES: + proc.join() + log.info("System exiting") + sys.exit(0) def main(): @@ -39,19 +53,24 @@ def main(): Main process loop. """ - procs = [] - signal.signal(signal.SIGTERM, signal_handler) - signal.signal(signal.SIGINT, signal_handler) + # Setup logging + log.setLevel(DEBUG) + ch = StreamHandler() + ch.setLevel(DEBUG) + formatter = Formatter('[%(asctime)s] [%(levelname)s] [%(name)s] [%(message)s]') + ch.setFormatter(formatter) + log.addHandler(ch) + + 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 + mgr = periph_manager() + _PROCESSES.append( + mpm.spawn_discovery_process({'serial': mgr.get_serial()}, shared)) + _PROCESSES.append( + mpm.spawn_rpc_process(mpm.types.MPM_RPC_PORT, shared, mgr)) + signal.signal(signal.SIGTERM, kill_time) + signal.signal(signal.SIGINT, kill_time) + signal.pause() if __name__ == '__main__': exit(not main()) - diff --git a/mpm/python/usrp_mpm/CMakeLists.txt b/mpm/python/usrp_mpm/CMakeLists.txt index f8f94bb5d..12bcdac11 100644 --- a/mpm/python/usrp_mpm/CMakeLists.txt +++ b/mpm/python/usrp_mpm/CMakeLists.txt @@ -18,15 +18,16 @@ ######################################################################## # This file included, use CMake directory variables ######################################################################## - -SET(USRP_MPM_FILES +SET(USRP_MPM_FILES ${USRP_MPM_FILES}) +SET(USRP_MPM_TOP_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 - ${CMAKE_CURRENT_SOURCE_DIR}/periph_manager - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager - PARENT_SCOPE ) +LIST(APPEND USRP_MPM_FILES ${USRP_MPM_TOP_FILES}) +ADD_SUBDIRECTORY(periph_manager) +ADD_SUBDIRECTORY(dboard_manager) + +SET(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE) diff --git a/mpm/python/usrp_mpm/__init__.py b/mpm/python/usrp_mpm/__init__.py index c349d3d77..c7043c70c 100644 --- a/mpm/python/usrp_mpm/__init__.py +++ b/mpm/python/usrp_mpm/__init__.py @@ -19,7 +19,7 @@ MPM Module """ from discovery import spawn_discovery_process -from rpc_process import spawn_rpc_process +from rpc_server import spawn_rpc_process import types import periph_manager import dboard_manager diff --git a/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt b/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt new file mode 100644 index 000000000..b642d506e --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/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 ${USRP_MPM_FILES}) +SET(USRP_MPM_DBMGR_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/base.py + ${CMAKE_CURRENT_SOURCE_DIR}/magnesium.py + ${CMAKE_CURRENT_SOURCE_DIR}/eiscat.py + ${CMAKE_CURRENT_SOURCE_DIR}/unknown.py + ) +LIST(APPEND USRP_MPM_FILES ${USRP_MPM_DBMGR_FILES}) +SET(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE) diff --git a/mpm/python/usrp_mpm/dboard_manager/__init__.py b/mpm/python/usrp_mpm/dboard_manager/__init__.py index 774f348d4..02746e78f 100644 --- a/mpm/python/usrp_mpm/dboard_manager/__init__.py +++ b/mpm/python/usrp_mpm/dboard_manager/__init__.py @@ -20,6 +20,7 @@ dboards module __init__.py from .. import libpyusrp_periphs as lib from magnesium import magnesium from eiscat import eiscat +from test import test from unknown import unknown hw_pids = { diff --git a/mpm/python/usrp_mpm/dboard_manager/base.py b/mpm/python/usrp_mpm/dboard_manager/base.py index bf0a115cc..257a2424d 100644 --- a/mpm/python/usrp_mpm/dboard_manager/base.py +++ b/mpm/python/usrp_mpm/dboard_manager/base.py @@ -30,6 +30,7 @@ class dboard_manager(object): Sanitizes arguments before calling C++ functions. Ties various constants to specific daughterboard class """ + _eeprom = {} def __init__(self, eeprom={}): self._eeprom = eeprom diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index 2201064ad..d48768208 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -20,6 +20,7 @@ magnesium dboard implementation module from base import dboard_manager from base import lib from base import log +import struct class magnesium(dboard_manager): hw_pid = 2 @@ -47,4 +48,3 @@ class magnesium(dboard_manager): # magnesium eeprom contains # nothing return struct.unpack_from("x", data) - diff --git a/mpm/python/usrp_mpm/dboard_manager/test.py b/mpm/python/usrp_mpm/dboard_manager/test.py new file mode 100644 index 000000000..b2e422bb4 --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/test.py @@ -0,0 +1,57 @@ +# +# 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/>. +# +""" +magnesium dboard implementation module +""" +from base import dboard_manager +from base import log + + +class fake_spi(object): + def __init__(self, addr): + self.addr = addr + + +class test_device(object): + def __init__(self, dev1, dev2, dev3): + self.dev1 = fake_spi(dev1) + self.dev2 = fake_spi(dev2) + self.dev3 = fake_spi(dev3) + + def test_method1(self, argument): + return argument + + +class test(dboard_manager): + hw_pid = 234 + special_eeprom_addrs = {"special0": "something"} + spi_chipselect = {"0": "dev1", "1": "dev2", "2": "dev3"} + spidevs = {} + + def __init__(self, *args, **kwargs): + # eeprom_data is a tuple (head_dict, raw_data) + super(test, self).__init__(*args, **kwargs) + # I'm the test device, I can fake out my EEPROM + self.dev1 = "0" + self.dev2 = "1" + self.dev3 = "2" + + def init_device(self): + self._device = test_device(self.dev1, self.dev2, self.dev3) + + + diff --git a/mpm/python/usrp_mpm/discovery.py b/mpm/python/usrp_mpm/discovery.py index 727fe2b94..174866498 100644 --- a/mpm/python/usrp_mpm/discovery.py +++ b/mpm/python/usrp_mpm/discovery.py @@ -68,9 +68,9 @@ def _discovery_process(device_info, state): try: while True: data, sender = sock.recvfrom(4096) - if data == "MPM-DISC": + if data.strip("\0") == "MPM-DISC": send_data = create_response_string() send_sock.sendto(send_data, sender) - except graceful_exit: + except: sock.close() - print("I'm done") + send_sock.close() diff --git a/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt new file mode 100644 index 000000000..879ac20c1 --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# 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 ${USRP_MPM_FILES}) +SET(USRP_MPM_PERIPHMGR_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in + ${CMAKE_CURRENT_SOURCE_DIR}/base.py + ${CMAKE_CURRENT_SOURCE_DIR}/n310.py + ) +LIST(APPEND USRP_MPM_FILES ${USRP_MPM_TOP_FILES}) +SET(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE) diff --git a/mpm/python/usrp_mpm/periph_manager/__init__.py b/mpm/python/usrp_mpm/periph_manager/__init__.py.in index 96eecf62e..0956b849e 100644 --- a/mpm/python/usrp_mpm/periph_manager/__init__.py +++ b/mpm/python/usrp_mpm/periph_manager/__init__.py.in @@ -24,6 +24,6 @@ from .. import dboard_manager from .. import types try: - from n310 import n310 as periph_manager + from ${MPM_DEVICE} import ${MPM_DEVICE} as periph_manager except ImportError: - raise("Could not import n310") + raise Exception("Could not import ${MPM_DEVICE}") diff --git a/mpm/python/usrp_mpm/periph_manager/n310.py b/mpm/python/usrp_mpm/periph_manager/n310.py index e270387f6..d1c31540b 100644 --- a/mpm/python/usrp_mpm/periph_manager/n310.py +++ b/mpm/python/usrp_mpm/periph_manager/n310.py @@ -27,7 +27,7 @@ class n310(periph_manager): dboard_eeprom_addrs = {"A": "something", "B": "else"} dboard_spimaster_addrs = {"A": "something", "B": "else"} - def __init__(self, eeprom_device, *args, **kwargs): + def __init__(self, *args, **kwargs): # First initialize parent class - will populate self._eeprom_head and self._eeprom_rawdata super(n310, self).__init__(*args, **kwargs) data = self.read_eeprom_v1(self._eeprom_rawdata) diff --git a/mpm/python/usrp_mpm/periph_manager/test.py b/mpm/python/usrp_mpm/periph_manager/test.py new file mode 100644 index 000000000..c9cbc1f3f --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/test.py @@ -0,0 +1,63 @@ +# +# 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/>. +# +""" +test periph_manager implementation module +""" +from base import periph_manager +from . import dboard_manager +import random +import string +import struct + + +class test(periph_manager): + hw_pids = "42" + mboard_eeprom_addr = None + dboard_eeprom_addrs = {"A": "something", "B": "else"} + dboard_spimaster_addrs = {"A": "something", "B": "else"} + + def __init__(self, *args, **kwargs): + # First initialize parent class - will populate self._eeprom_head and self._eeprom_rawdata + # super(n310, self).__init__(*args, **kwargs) + # if header.get("dataversion", 0) == 1: + self._eeprom = self.read_eeprom_fake() + self._serial = "AABBCCDDEEFF" + + # I'm the test periph_manager, I know I have test dboards attached + self.dboards = { + "A": dboard_manager.test(self.read_db_eeprom_random()), + "B": dboard_manager.test(self.read_db_eeprom_random()) + } + + def read_eeprom_fake(self): + fake_eeprom = { + "magic": 42, + "crc": 4242, + "data_version": 42, + "hw_pid": 42, + "hw_rev": 5 + } + + return fake_eeprom + + def read_db_eeprom_random(self): + fake_eeprom = { + "serial": ''.join( + random.choice("ABCDEF" + string.digits) + for _ in range(16)) + } + return fake_eeprom diff --git a/mpm/python/usrp_mpm/rpc_process.py b/mpm/python/usrp_mpm/rpc_process.py deleted file mode 100644 index b8783f325..000000000 --- a/mpm/python/usrp_mpm/rpc_process.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# 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 index a5dda0826..ddb588aa6 100644 --- a/mpm/python/usrp_mpm/rpc_server.py +++ b/mpm/python/usrp_mpm/rpc_server.py @@ -17,25 +17,57 @@ """ Implemented RPC Servers """ - from __future__ import print_function +from gevent.server import StreamServer +from types import graceful_exit, MPM_RPC_PORT from mprpc import RPCServer -from usrp_mpm import periphs +from six import iteritems +import time + +from multiprocessing import Process +class MPMServer(RPCServer): + _db_methods = {} + def __init__(self, state, mgr): + self._state = state + # Instead do self.mboard = periphs.init_periph_manager(args...) + self.periph_manager = mgr + for db_slot, db in iteritems(mgr.dboards): + methods = (m for m in dir(db) if not m.startswith('_') and callable(getattr(db, m))) + for method in methods: + command_name = 'db_'+ db_slot + '_' + method + self._add_command(getattr(db,method), command_name) + db_methods = self._db_methods.get(db_slot, []) + db_methods.append(command_name) + self._db_methods.update({db_slot: db_methods}) -class EchoServer(RPCServer): - def echo(self, arg): - print(arg) - return arg + # When we do init we can just add dboard/periph_manager methods with setattr(self, method) + # Maybe using partial + # To remove methods again we also have to remove them from self._methods dict (they're cached) + super(MPMServer, self).__init__() + def _add_command(self, function, command): + setattr(self, command, function) -class ClaimServer(RPCServer): - def __init__(self, state): - self._state = state - super(ClaimServer, self).__init__() + + def list_methods(self): + """ + Returns all public methods of this RPC server + """ + 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 + + def ping(self, data=None): + """ + Take in data as argument and send it back + """ + return data def claim(self, token): - 'claim `token` - claims the MPM device with given 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 @@ -45,28 +77,33 @@ class ClaimServer(RPCServer): return True def unclaim(self, token): - 'unclaim `token` - unclaims the MPM device if it is claimed with this 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 +def _rpc_server_process(shared_state, port, mgr): + """ + Start the RPC server + """ + server = StreamServer(('0.0.0.0', port), handle=MPMServer(shared_state, mgr)) + try: + server.serve_forever() + except: + server.close() -class MPMServer(RPCServer): - def __init__(self, state): - # Instead do self.mboard = periphs.init_periph_manager(args...) - self.periph_manager = periphs.init_periph_manager() - # When we do init we can just add dboard/periph_manager methods with setattr(self, method) - # Maybe using partial - # To remove methods again we also have to remove them from self._methods dict (they're cached) - def get_clock_id(self, dboard): - dboard = getattr(self.mboard, "get_dboard_"+dboard) - clk = dboard.get_clock_gen() - return clk.get_chip_id() +def spawn_rpc_process(state, udp_port, mgr): + """ + Returns a process that contains the RPC server + """ + + p_args = [udp_port, state, mgr] + p = Process(target=_rpc_server_process, args=p_args) + p.start() + return p diff --git a/mpm/tools/CMakeLists.txt b/mpm/tools/CMakeLists.txt new file mode 100644 index 000000000..107aedeae --- /dev/null +++ b/mpm/tools/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# 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/>. +# + +INSTALL(PROGRAMS + rpc_shell.py + mpm_debug.py + DESTINATION ${RUNTIME_DIR}) diff --git a/mpm/python/test_rpc.py b/mpm/tools/mpm_debug.py index 1a97a103c..1a97a103c 100755 --- a/mpm/python/test_rpc.py +++ b/mpm/tools/mpm_debug.py diff --git a/mpm/tools/rpc_shell.py b/mpm/tools/rpc_shell.py index ef3c73614..36c16880a 100755 --- a/mpm/tools/rpc_shell.py +++ b/mpm/tools/rpc_shell.py @@ -22,35 +22,49 @@ RPC shell to debug USRP MPM capable devices import sys import cmd import types -from functools import partial from mprpc import RPCClient from mprpc.exceptions import RPCError from usrp_mpm import types +from importlib import import_module -def rpc_template(obj, command, args): - try: - if args: - response = obj.client.call(command, args) - else: - response = obj.client.call(command) - except RPCError as e: - print("RPC Command failed!") - print("Error: {}".format(e)) - return - if isinstance(response, bool): - if response: - print("Commend executed successfully!") - return - print("Command failed!") - return - print(response) class RPCShell(cmd.Cmd): - prompt="MPM> " + prompt = "MPM> " client = None remote_methods = [] + def rpc_template(self, command, args=None): + """Template function to create new RPC shell commands""" + eval_preamble = "=" + try: + if args: + if isinstance(args, list): + parsed_args = [ + eval(a.lstrip(eval_preamble)) + if a.startswith(eval_preamble) else a for a in args + ] + response = self.client.call(command, parsed_args) + else: + response = self.client.call( + command, + eval(args.lstrip(eval_preamble)) + if args.startswith(eval_preamble) else args) + else: + response = self.client.call(command) + except RPCError as e: + print("RPC Command failed!") + print("Error: {}".format(e)) + return + if isinstance(response, bool): + if response: + print("Commend executed successfully!") + return + print("Command failed!") + return + print(response) + def do_connect(self, host, port=types.MPM_RPC_PORT): + """connect to a remote RPC serverconnect <host> (port=MPM_RPC_PORT)""" try: self.client = RPCClient(host, port) except: @@ -61,6 +75,7 @@ class RPCShell(cmd.Cmd): self.add_command(*method) def do_disconnect(self, args): + """disconnect from the RPC server""" if self.client: try: self.client.close() @@ -68,15 +83,21 @@ class RPCShell(cmd.Cmd): print("Error while closing the connection") print("Error: {}".format(e)) for method in self.remote_methods: - delattr(self, "do_"+method) + delattr(self, "do_" + method) self.remote_methods = [] self.client = None + def do_import(self, args): + """import a python module into the global namespace""" + globals()[args] = import_module(args) + + def do_EOF(self, args): + exit(0) def add_command(self, command, docs): - new_command = partial(rpc_template, self, str(command)) + def new_command(args): self.rpc_template(str(command), args) new_command.__doc__ = docs - setattr(self, "do_"+command, new_command) + setattr(self, "do_" + command, new_command) self.remote_methods.append(command) def run(self): @@ -92,5 +113,4 @@ class RPCShell(cmd.Cmd): if __name__ == "__main__": my_shell = RPCShell() - exit(not(my_shell.run())) - + exit(not (my_shell.run())) |