diff options
39 files changed, 1190 insertions, 152 deletions
diff --git a/mpm/CMakeLists.txt b/mpm/CMakeLists.txt index 73ec07657..0de4ad262 100644 --- a/mpm/CMakeLists.txt +++ b/mpm/CMakeLists.txt @@ -61,12 +61,25 @@ 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}") MESSAGE(STATUS "Boost libraries: ${Boost_LIBRARIES}") ######################################################################## +# Setup Python API +######################################################################## + +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}") + + +######################################################################## # Setup library configuration ######################################################################## SET(CMAKE_CXX_STANDARD 11) @@ -92,16 +105,9 @@ ENDIF(MPM_DEVICE STREQUAL tests) MESSAGE("usrp_periphs objects: ${usrp_periphs_objects}") ADD_LIBRARY(usrp-periphs SHARED ${usrp_periphs_objects}) -TARGET_LINK_LIBRARIES(usrp-periphs udev) -######################################################################## -# Setup Python API -######################################################################## +TARGET_LINK_LIBRARIES(usrp-periphs + udev + ${Boost_LIBRARIES} +) -SET(PYTHON_ADDITIONAL_VERSIONS 2.7 3.4 3.5) -FIND_PACKAGE(PythonInterp) -unset(PYTHON_LIBRARY) -unset(PYTHON_EXECUTABLE) -FIND_PACKAGE(PythonLibs) ADD_SUBDIRECTORY(python) - -######################################################################## diff --git a/mpm/dboards/magnesium_manager.hpp b/mpm/dboards/magnesium_manager.hpp index ca8a7e123..3c8f038ed 100644 --- a/mpm/dboards/magnesium_manager.hpp +++ b/mpm/dboards/magnesium_manager.hpp @@ -48,3 +48,13 @@ namespace mpm { namespace dboards { }}; + +#ifdef LIBMPM_PYTHON +void export_dboards(){ + LIBMPM_BOOST_PREAMBLE("dboards") + bp::class_<mpm::dboards::magnesium_periph_manager>("magnesium_periph_manager", bp::init<std::string, std::string>()) + .def("get_clock_ctrl", &mpm::dboards::magnesium_periph_manager::get_clock_ctrl) + .def("get_radio_ctrl", &mpm::dboards::magnesium_periph_manager::get_radio_ctrl) + ; +} +#endif diff --git a/mpm/include/lmk/lmk04828_spi_iface.hpp b/mpm/include/lmk/lmk04828_spi_iface.hpp index 013271af1..fa11029a8 100644 --- a/mpm/include/lmk/lmk04828_spi_iface.hpp +++ b/mpm/include/lmk/lmk04828_spi_iface.hpp @@ -25,3 +25,16 @@ private: void spi_write(std::vector<uint32_t> writes); uint8_t spi_read(uint32_t addr); }; + +#ifdef LIBMPM_PYTHON +void export_lmk(){ + LIBMPM_BOOST_PREAMBLE("lmk04828") + 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("get_chip_id", &lmk04828_iface::get_chip_id) + .def("init", &lmk04828_iface::init) + .def("send_sysref_pulse", &lmk04828_iface::send_sysref_pulse) + ; +} +#endif diff --git a/mpm/include/mpm/spi/spidev_iface.hpp b/mpm/include/mpm/spi/spidev_iface.hpp index fb82ffade..ef5303f7b 100644 --- a/mpm/include/mpm/spi/spidev_iface.hpp +++ b/mpm/include/mpm/spi/spidev_iface.hpp @@ -57,3 +57,36 @@ namespace mpm { namespace spi { }}; /* namespace mpm */ +//void export_spi(){ + //// Register submodule spi + //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_<spi_lock, boost::noncopyable, boost::shared_ptr<spi_lock> >("spi_lock", bp::no_init) + //.def("make", &spi_lock::make) + //.def("get_spidev", &spi_lock::get_spidev) + //; + + //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/lib/CMakeLists.txt b/mpm/lib/CMakeLists.txt index 19dbf6dce..647697c84 100644 --- a/mpm/lib/CMakeLists.txt +++ b/mpm/lib/CMakeLists.txt @@ -25,4 +25,8 @@ ADD_SUBDIRECTORY(mykonos) ADD_SUBDIRECTORY(lmk04828) USRP_PERIPHS_ADD_OBJECT(periphs - print_foo.cpp) + net_helper.cpp + udev_helper.cpp + xbar_iface.cpp + print_foo.cpp + ) diff --git a/mpm/lib/lmk04828/CMakeLists.txt b/mpm/lib/lmk04828/CMakeLists.txt index 4235cb34a..b3621034a 100644 --- a/mpm/lib/lmk04828/CMakeLists.txt +++ b/mpm/lib/lmk04828/CMakeLists.txt @@ -2,7 +2,9 @@ MACRO(ETTUS_PYTHON_GEN_SOURCE pyfile outfile) #ensure that the directory exists for outfile GET_FILENAME_COMPONENT(outfile_dir ${outfile} PATH) FILE(MAKE_DIRECTORY ${outfile_dir}) - + IF(NOT PYTHON_EXECUTABLE) + MESSAGE( FATAL_ERROR "No python executable found to generate ic_regmaps!" ) + ENDIF(NOT PYTHON_EXECUTABLE) #make the outfile depend on the python script ADD_CUSTOM_COMMAND( OUTPUT ${outfile} DEPENDS ${pyfile} ${ETTUS_PYTHON_GEN_SOURCE_DEPS} diff --git a/mpm/lib/mykonos/ad937x_ctrl.hpp b/mpm/lib/mykonos/ad937x_ctrl.hpp index defb57fa2..12c165dab 100644 --- a/mpm/lib/mykonos/ad937x_ctrl.hpp +++ b/mpm/lib/mykonos/ad937x_ctrl.hpp @@ -70,3 +70,32 @@ protected: static std::set<size_t> _get_valid_fir_lengths(const std::string& which); }; + +#ifdef LIBMPM_PYTHON +void export_mykonos(){ + LIBMPM_BOOST_PREAMBLE("ad937x") + + bp::class_<ad937x_ctrl, boost::noncopyable, std::shared_ptr<ad937x_ctrl> >("ad937x_ctrl", bp::no_init) + .def("make", &ad937x_ctrl::make) + .def("get_rf_freq_range", &ad937x_ctrl::get_rf_freq_range) + .def("get_bw_filter_range", &ad937x_ctrl::get_bw_filter_range) + .def("get_clock_rates", &ad937x_ctrl::get_clock_rates) + .def("get_gain_range", &ad937x_ctrl::get_gain_range) + .def("get_product_id", &ad937x_ctrl::get_product_id) + .def("get_device_rev", &ad937x_ctrl::get_device_rev) + .def("get_api_version", &ad937x_ctrl::get_api_version) + .def("get_arm_version", &ad937x_ctrl::get_arm_version) + .def("set_bw_filter", &ad937x_ctrl::set_bw_filter) + .def("set_gain", &ad937x_ctrl::set_gain) + .def("set_agc_mode", &ad937x_ctrl::set_agc_mode) + .def("set_clock_rate", &ad937x_ctrl::set_clock_rate) + .def("enable_channel", &ad937x_ctrl::enable_channel) + .def("set_freq", &ad937x_ctrl::set_freq) + .def("get_freq", &ad937x_ctrl::get_freq) + .def("set_fir", &ad937x_ctrl::set_fir) + .def("get_fir", &ad937x_ctrl::get_fir) + .def("get_temperature", &ad937x_ctrl::get_temperature) + ; +} +#endif + diff --git a/mpm/lib/net_helper.cpp b/mpm/lib/net_helper.cpp new file mode 100644 index 000000000..0da8de3cf --- /dev/null +++ b/mpm/lib/net_helper.cpp @@ -0,0 +1,118 @@ +// +// 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/>. +// + +#include "net_helper.hpp" +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <netdb.h> +#include <ifaddrs.h> +#include <linux/if_link.h> +#include <linux/if_packet.h> +#include <iomanip> +#include <iostream> +#include <string> +#include <sstream> +#include <cstring> +#include <cstdint> + +namespace mpm { +namespace network{ + +template <typename ArrayType> +std::string bytearray_to_string(const ArrayType array[], size_t elements) { + std::stringstream result; + for (size_t i = 0; i < elements; i++) { + result << std::uppercase << std::setfill('0') + << std::setw(sizeof(array[i]) * + 2) // always produce 2 hex values for each byte + << std::hex << +array[i]; // Implicit integer promotion + } + return result.str(); +} + +void print_net_ifaces(net_ifaces my_ifaces) { + /* take in a net_ifaces and pretty print information + about all detected network interfaces */ + for (const auto& iface : my_ifaces) { + std::cout << "interface: " << iface.first << std::endl; + std::cout << "\tMAC: " << iface.second.mac_addr << std::endl; + for (const auto& addr : iface.second.ip_addr) { + std::cout << "\tip address: " << addr << std::endl; + } + } +} + +net_ifaces get_net_map() { + /* Get a map containing a string and a net_iface struct + to describe all adresses assigned to a interface */ + struct ifaddrs *ifaddr, *ifa; + int family, s; + char host[NI_MAXHOST]; + net_ifaces net_map; + + if (getifaddrs(&ifaddr) == -1) { + throw uhd::system_error(str(boost::format("Error: %s") % strerror(errno))); + } + + /* Walk through linked list, maintaining head pointer so we + can free list later */ + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + /* Put the interaface name into the map, if it already exists + we get an iterator to the existing element */ + auto result = net_map.emplace( + std::make_pair(std::string(ifa->ifa_name), net_iface())); + auto current_iface = result.first; + + family = ifa->ifa_addr->sa_family; + if (family == AF_INET || family == AF_INET6) { + s = getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (s != 0) { + printf("getnameinfo() failed: %s\n", gai_strerror(s)); + return net_map; + } + current_iface->second.ip_addr.push_back(std::string(host)); + } else if (family == AF_PACKET && ifa->ifa_data != NULL) { + struct sockaddr_ll* s = (struct sockaddr_ll*)ifa->ifa_addr; + uint8_t mac_addr[6]; + memcpy(&mac_addr, s->sll_addr, 6); + current_iface->second.mac_addr = bytearray_to_string(mac_addr, 6); + } + } + freeifaddrs(ifaddr); + return net_map; +} + +std::vector<std::string> get_if_addrs(const std::string& mac_addr) { + /* Convenience wrapper to return all adresses associated with one + mac address */ + net_ifaces my_map = get_net_map(); + for (const auto& iface : my_map) { // find + if (iface.second.mac_addr == mac_addr) { + return iface.second.ip_addr; + } + } + return std::vector<std::string>(); +} +} +} diff --git a/mpm/lib/net_helper.hpp b/mpm/lib/net_helper.hpp new file mode 100644 index 000000000..b07e43ccc --- /dev/null +++ b/mpm/lib/net_helper.hpp @@ -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/>. +// + +#include <map> +#include <vector> +#include <string> + +namespace mpm { +namespace network { + +/*! + * A struct describing a single network interface + */ +using net_iface = struct net_iface { + /*! MAC address of the interface in the form AABBCCDDEEFF */ + std::string mac_addr; + /*! vector of associated IP addresses, contains both IPv4 and IPv6 */ + std::vector<std::string> ip_addr; +}; + +/*! + * net_ifaces contains a <interfaces name, net_iface> pair + * describing mac address and associated ip addresses for + * each interface + */ +using net_ifaces = std::map<std::string, net_iface>; + +/*! + * Convenience function to get all ip addresses of one MAC address + * \param MAC address in the form AABBCCDDEEFF + * \return vector of strings containing all IP addresses with this MAC address + */ +std::vector<std::string> get_if_addrs(const std::string& mac_addr); + +/*! + * Get information about all interfaces on this system + * \return a map with interface names as keys and the interfaces information as value + */ +net_ifaces get_net_map(); + +/*! + * Pretty print net_ifaces in the style of `ip addr` + * \param interface map net_ifaces to print + */ +void print_net_ifaces(net_ifaces my_ifaces); +} +} + +#ifdef LIBMPM_PYTHON +void export_net_iface(){ + LIBMPM_BOOST_PREAMBLE("network") + bp::def("get_if_addrs", &mpm::network::get_if_addrs); +} +#endif + diff --git a/mpm/lib/udev_helper.cpp b/mpm/lib/udev_helper.cpp new file mode 100644 index 000000000..ba12f6667 --- /dev/null +++ b/mpm/lib/udev_helper.cpp @@ -0,0 +1,93 @@ +// +// 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/>. +// + +#include "udev_helper.hpp" +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <boost/make_shared.hpp> +#include <boost/crc.hpp> +#include <utility> +#include <iostream> +#include <string> +#include <cstring> +#include <fstream> + +using namespace mpm; + +udev_helper::udev_helper(){ + _udev = udev_new(); + if (!_udev) { + throw uhd::os_error("Failed to create udev!"); + } + _enumerate = udev_enumerate_new(_udev); + +} + +udev_helper::~udev_helper(){ + udev_enumerate_unref(_enumerate); + udev_unref(_udev); +} +std::string udev_helper::get_eeprom(const std::string &address){ + udev_list_entry *devices, *dev_list_entry; + udev_device *dev, *parent; + + parent = udev_device_new_from_subsystem_sysname(_udev, "platform", address.c_str()); + if (parent == NULL){ + return std::string(); + } + udev_enumerate_add_match_parent(_enumerate, parent); + udev_enumerate_add_match_subsystem(_enumerate, "nvmem"); + udev_enumerate_scan_devices(_enumerate); + + devices = udev_enumerate_get_list_entry(_enumerate); + if (devices == NULL){ + return std::string(); + } + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path = NULL, *sys_path = NULL; + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(_udev, path); + sys_path = udev_device_get_syspath(dev); + udev_device_unref(dev); + return "/sys" + std::string(sys_path) + "/nvmem"; + } + return std::string(); +} + +std::vector<std::string> udev_helper::get_spidev_nodes(const std::string &spi_master){ + udev_list_entry *devices, *dev_list_entry; + udev_device *dev, *parent; + + parent = udev_device_new_from_subsystem_sysname(_udev, "platform", spi_master.c_str()); + udev_enumerate_add_match_parent(_enumerate, parent); + udev_enumerate_add_match_subsystem(_enumerate, "spidev"); + udev_enumerate_scan_devices(_enumerate); + + devices = udev_enumerate_get_list_entry(_enumerate); + std::vector<std::string> found_dev_nodes; + if (devices != NULL){ + udev_list_entry_foreach(dev_list_entry, devices){ + const char *path, *dev_node; + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(_udev, path); + dev_node = udev_device_get_devnode(dev); + found_dev_nodes.push_back(std::string(dev_node)); + udev_device_unref(dev); + } + } + return found_dev_nodes; +} diff --git a/mpm/lib/udev_helper.hpp b/mpm/lib/udev_helper.hpp new file mode 100644 index 000000000..055a93cee --- /dev/null +++ b/mpm/lib/udev_helper.hpp @@ -0,0 +1,62 @@ +// +// 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/>. +// + +#include <libudev.h> +#include <string> +#include <vector> + +namespace mpm { + /*! + * The udev_helper class: + * + * talks to libudev and holds a udev context. Device enumeration is done + * once during initialization. + * On destruction the udev context is unreferenced again. + */ + class udev_helper{ + public: + udev_helper(); + ~udev_helper(); + /*! + * Return the nvmem device associated with the parent address + * \param address of the parent platform driver + * \return a string containing the name of file of the device in /sys + */ + std::string get_eeprom(const std::string &address); + /*! + * Find spidevices associated with the spi_master + * \param address of the parent platform driver + * \return a vector of string containing the device paths is /dev + */ + std::vector<std::string> get_spidev_nodes(const std::string &spi_master); + + private: + udev *_udev; + udev_enumerate *_enumerate; + }; +} + +#ifdef LIBMPM_PYTHON +void export_udev_helper(){ + LIBMPM_BOOST_PREAMBLE("udev") + bp::class_<mpm::udev_helper>("udev_helper", bp::init<>()) + .def("get_eeprom", &mpm::udev_helper::get_eeprom) + .def("get_spidev_nodes", &mpm::udev_helper::get_spidev_nodes) + ; +} +#endif + diff --git a/mpm/lib/xbar_iface.cpp b/mpm/lib/xbar_iface.cpp new file mode 100644 index 000000000..21b60d131 --- /dev/null +++ b/mpm/lib/xbar_iface.cpp @@ -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/>. +// + +#include "xbar_iface.hpp" +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <sys/ioctl.h> +#include <fcntl.h> + +using namespace mpm; + +std::mutex xbar_iface::_lock; // Initialize lock for all objects + +xbar_iface::xbar_iface(const std::string &device){ + _fd = open(device.c_str(), O_RDWR); +} + +xbar_iface::~xbar_iface(){ + close(_fd); +} + +void xbar_iface::set_route(uint8_t dst_addr, uint8_t dst_port) { + std::lock_guard<std::mutex> lock(_lock); + rfnoc_crossbar_cmd cmd = {.dest_addr = dst_addr, .dest_port = dst_port}; + int err = ioctl(_fd, RFNCBWROUTIOC, &cmd); + if (err < 0) { + throw uhd::os_error(str(boost::format("setting crossbar route failed! Error: %d") % err)); + } +} + +void xbar_iface::del_route(uint8_t dst_addr, uint8_t dst_port){ + std::lock_guard<std::mutex> lock(_lock); + rfnoc_crossbar_cmd cmd = {.dest_addr = dst_addr, .dest_port = dst_port}; + int err = ioctl(_fd, RFNCDELROUTIOC, &cmd); + if (err < 0){ + throw uhd::os_error(str(boost::format("deleting crossbar route failed! Error: %d") % err)); + } +} + +xbar_iface::sptr xbar_iface::make(const std::string &device){ + return std::make_shared<xbar_iface>(device); +} diff --git a/mpm/lib/xbar_iface.hpp b/mpm/lib/xbar_iface.hpp new file mode 100644 index 000000000..9b17ed97b --- /dev/null +++ b/mpm/lib/xbar_iface.hpp @@ -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/>. +// +#pragma once +#include <boost/noncopyable.hpp> +#include <memory> +#include <mutex> +#include <cstdint> + +namespace mpm{ + +/*! + * Crossbar route command + */ +using rfnoc_crossbar_cmd = struct rfnoc_crossbar_cmd { + /*! destination address */ + uint8_t dest_addr; + /*! destination port */ + uint8_t dest_port; +}; + +#define RFNCBWROUTIOC _IOW('R', 1, struct rfnoc_crossbar_cmd) +#define RFNCDELROUTIOC _IOW('D', 1, struct rfnoc_crossbar_cmd) + +/*! + * Crossbar interface class holding a crossbar context + */ +class xbar_iface: boost::noncopyable{ +public: + // use static mutex! lock_guard + using sptr = std::shared_ptr<xbar_iface>; + static sptr make(const std::string &device); + void set_route(uint8_t dst_addr, uint8_t dst_port); + void del_route(uint8_t dst_addr, uint8_t dst_port); + ~xbar_iface(); + xbar_iface(const std::string &device); + +private: + static std::mutex _lock; + int _fd; +}; +} + + +#ifdef LIBMPM_PYTHON +void export_xbar(){ + LIBMPM_BOOST_PREAMBLE("xbar") + bp::class_<mpm::xbar_iface, boost::noncopyable, std::shared_ptr<mpm::xbar_iface> >("xbar", bp::no_init) + .def("make", &mpm::xbar_iface::make) + .staticmethod("make") + .def("set_route", &mpm::xbar_iface::set_route) + .def("del_route", &mpm::xbar_iface::del_route) + ; +} +#endif + diff --git a/mpm/python/CMakeLists.txt b/mpm/python/CMakeLists.txt index 7d3b251d7..7a88abfc7 100644 --- a/mpm/python/CMakeLists.txt +++ b/mpm/python/CMakeLists.txt @@ -24,13 +24,14 @@ 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_INCLUDE_DIRECTORIES(pyusrp_periphs PUBLIC + ${PYTHON_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/lib/ + ${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) @@ -43,10 +44,10 @@ 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}) + 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} -E touch ${OUTPUT} + DEPENDS ${USRP_MPM_FILES}) ADD_CUSTOM_TARGET(usrp_mpm ALL DEPENDS ${OUTPUT} pyusrp_periphs) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c diff --git a/mpm/python/converters.hpp b/mpm/python/converters.hpp new file mode 100644 index 000000000..dc977b698 --- /dev/null +++ b/mpm/python/converters.hpp @@ -0,0 +1,105 @@ +// +// 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/>. +// + +#pragma once + +#include <boost/python.hpp> +#include <boost/python/stl_iterator.hpp> +#include <vector> +#include <string> + +namespace bp = boost::python; + +template<typename MapType> +struct map_to_python_dict +{ + static PyObject* convert(MapType const& input_map) + { + bp::dict py_dict; + for (const auto& element: input_map){ + py_dict[element.first] = element.second; + } + return bp::incref(py_dict.ptr()); + } + +}; + +template<typename Container> +struct iterable_to_python_list +{ + static PyObject* convert(Container const& input) + { + bp::list py_list; + for (const auto& element: input){ + py_list.append(element); + } + return bp::incref(py_list.ptr()); + } +}; + +// Converter for std::vector / std::list arguments from python iterables +struct iterable_converter +{ + template <typename Container> + iterable_converter& + from_python() + { + bp::converter::registry::push_back( + &iterable_converter::convertible, + &iterable_converter::construct<Container>, + bp::type_id<Container>()); + return *this; + } + + static void* convertible(PyObject* object) + { + return PyObject_GetIter(object) ? object : NULL; + } + + template <typename Container> + static void construct( + PyObject* object, + bp::converter::rvalue_from_python_stage1_data* data) + { + // Object is a borrowed reference, so create a handle indicting it is + // borrowed for proper reference counting. + bp::handle<> handle(bp::borrowed(object)); + + // Obtain a handle to the memory block that the converter has allocated + // for the C++ type. + typedef bp::converter::rvalue_from_python_storage<Container> + storage_type; + void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes; + + typedef bp::stl_input_iterator<typename Container::value_type> + iterator; + + // Allocate the C++ type into the converter's memory block, and assign + // its handle to the converter's convertible variable. The C++ + // container is populated by passing the begin and end iterators of + // the python object to the container's constructor. + new (storage) Container( + iterator(bp::object(handle)), // begin + iterator()); // end + data->convertible = storage; + } +}; + +void export_converter(){ + // LIBMPM_BOOST_PREAMBLE("helper") + bp::to_python_converter<std::vector< std::string >, iterable_to_python_list<std::vector< std::string > >, false>(); +} diff --git a/mpm/python/copy_python_module.cmake b/mpm/python/copy_python_module.cmake new file mode 100644 index 000000000..1b36d4fab --- /dev/null +++ b/mpm/python/copy_python_module.cmake @@ -0,0 +1,4 @@ +SET(BINARY_DIR "" CACHE STRING "") +SET(SOURCE_DIR "" CACHE STRING "") +FILE(COPY ${SOURCE_DIR}/usrp_mpm/ DESTINATION ${BINARY_DIR}/usrp_mpm + FILES_MATCHING PATTERN *.py) diff --git a/mpm/python/lib_helper.cpp b/mpm/python/lib_helper.cpp new file mode 100644 index 000000000..5948628f8 --- /dev/null +++ b/mpm/python/lib_helper.cpp @@ -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/>. +// + +#include "lib_helper.hpp" +#include "converters.hpp" +#include "../lib/udev_helper.hpp" +#include "../lib/net_helper.hpp" +#include <boost/python.hpp> + +namespace bp = boost::python; + +void export_helper(){ + //Register submodule types + bp::object helper_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs.helper")))); + bp::scope().attr("helper") = helper_module; + bp::scope io_scope = helper_module; + + bp::class_<mpm::udev_helper>("udev_helper", bp::init<>()) + .def("get_eeprom", &mpm::udev_helper::get_eeprom) + ; + bp::def("get_if_addrs", &mpm::network::get_if_addrs); + bp::to_python_converter<std::vector< std::string >, iterable_to_python_list<std::vector< std::string > >, false>(); +} + diff --git a/mpm/python/lib_periphs.cpp b/mpm/python/lib_periphs.cpp deleted file mode 100644 index 030752ede..000000000 --- a/mpm/python/lib_periphs.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#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 deleted file mode 100644 index 2ea023c5c..000000000 --- a/mpm/python/lib_periphs.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -void export_lmk(); -void export_spi(); diff --git a/mpm/python/n310_periphs.cpp b/mpm/python/n310_periphs.cpp deleted file mode 100644 index 42fea61b1..000000000 --- a/mpm/python/n310_periphs.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#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 deleted file mode 100644 index b4e418947..000000000 --- a/mpm/python/n310_periphs.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void export_n3xx(); diff --git a/mpm/python/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs.cpp index 5a49398c4..348e19c5c 100644 --- a/mpm/python/pyusrp_periphs.cpp +++ b/mpm/python/pyusrp_periphs.cpp @@ -1,8 +1,39 @@ -#include "n310_periphs.hpp" -// #include "tests_periphs.hpp" -#include "lib_periphs.hpp" -#include <mpm/print_foo.hpp> +// +// 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/>. +// + +// include hackery to only include boost python and define the macro here #include <boost/python.hpp> +#define LIBMPM_PYTHON +#define LIBMPM_BOOST_PREAMBLE(module) \ + /* Register submodule types */ \ + namespace bp = boost::python; \ + bp::object py_module(bp::handle<>(bp::borrowed(PyImport_AddModule("libpyusrp_periphs." module)))); \ + bp::scope().attr(module) = py_module; \ + bp::scope io_scope = py_module; + +//#include "types.hpp" +#include "converters.hpp" +#include "net_helper.hpp" +#include "xbar_iface.hpp" +#include "udev_helper.hpp" +#include "mykonos/ad937x_ctrl.hpp" +#include "lmk/lmk04828_spi_iface.hpp" +//#include "lib_periphs.hpp" +//#include "dboards.hpp" #include <boost/noncopyable.hpp> namespace bp = boost::python; @@ -11,9 +42,13 @@ 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(); + export_converter(); + export_net_iface(); + //export_types(); + export_udev_helper(); + //export_spi(); + //export_lmk(); + export_mykonos(); + export_xbar(); + //export_dboards(); } diff --git a/mpm/python/setup.py.in b/mpm/python/setup.py.in index ad41eb480..2a63d14aa 100755 --- a/mpm/python/setup.py.in +++ b/mpm/python/setup.py.in @@ -38,7 +38,7 @@ setup(name='usrp_mpm', package_dir={ '': '${CMAKE_CURRENT_BINARY_DIR}' }, package_data={"usrp_mpm": ["*.so"]}, zip_safe=False, - packages=['usrp_mpm'], + packages=['usrp_mpm', 'usrp_mpm.periph_manager', 'usrp_mpm.dboard_manager'], install_requires=[ 'numpy' ]) diff --git a/mpm/python/tests_periphs.cpp b/mpm/python/tests_periphs.cpp index 15c1b08b6..a35d00265 100644 --- a/mpm/python/tests_periphs.cpp +++ b/mpm/python/tests_periphs.cpp @@ -1,3 +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/>. +// + #include "tests_periphs.hpp" #include <mpm/tests/tests_spi_iface.hpp> #include <mpm/spi_iface.hpp> @@ -11,7 +28,7 @@ void export_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<>()) + bp::class_<mpm::tests_spi_iface, bp::bases<mpm::spi_iface>, boost::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 index 4b978269d..e80dccdb2 100644 --- a/mpm/python/tests_periphs.hpp +++ b/mpm/python/tests_periphs.hpp @@ -1,3 +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/>. +// + #pragma once void export_tests(); diff --git a/mpm/python/usrp_mpm/CMakeLists.txt b/mpm/python/usrp_mpm/CMakeLists.txt index ad3ce41fd..f8f94bb5d 100644 --- a/mpm/python/usrp_mpm/CMakeLists.txt +++ b/mpm/python/usrp_mpm/CMakeLists.txt @@ -26,5 +26,7 @@ SET(USRP_MPM_FILES ${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 ) diff --git a/mpm/python/usrp_mpm/__init__.py b/mpm/python/usrp_mpm/__init__.py index dafb6940c..c349d3d77 100644 --- a/mpm/python/usrp_mpm/__init__.py +++ b/mpm/python/usrp_mpm/__init__.py @@ -21,3 +21,5 @@ MPM Module from discovery import spawn_discovery_process from rpc_process import spawn_rpc_process import types +import periph_manager +import dboard_manager diff --git a/mpm/python/usrp_mpm/dboard_manager/__init__.py b/mpm/python/usrp_mpm/dboard_manager/__init__.py new file mode 100644 index 000000000..774f348d4 --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/__init__.py @@ -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/>. +# +""" +dboards module __init__.py +""" +from .. import libpyusrp_periphs as lib +from magnesium import magnesium +from eiscat import eiscat +from unknown import unknown + +hw_pids = { + eiscat.hw_pid: eiscat, + magnesium.hw_pid: magnesium, +} diff --git a/mpm/python/usrp_mpm/dboard_manager/base.py b/mpm/python/usrp_mpm/dboard_manager/base.py new file mode 100644 index 000000000..bf0a115cc --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/base.py @@ -0,0 +1,37 @@ +# +# 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/>. +# +""" +dboard base implementation module +""" +from . import lib +import logging +import struct + +log = logging.Logger("usrp_mpm.dboards") + + +class dboard_manager(object): + """ + Holds shared pointer to wrapped C++ implementation. + Sanitizes arguments before calling C++ functions. + Ties various constants to specific daughterboard class + """ + def __init__(self, eeprom={}): + self._eeprom = eeprom + + def get_serial(self): + return self._eeprom.get("serial", "") diff --git a/mpm/python/usrp_mpm/dboard_manager/eiscat.py b/mpm/python/usrp_mpm/dboard_manager/eiscat.py new file mode 100644 index 000000000..f536d307b --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/eiscat.py @@ -0,0 +1,31 @@ +# +# 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/>. +# +""" +EISCAT rx board implementation module +""" +from base import dboard_manager +from base import lib +from base import log + + +class eiscat(dboard_manager): + hw_pid = 3 + special_eeprom_addrs = {"special0": "something"} + + def __init__(self, spidevs=[], *args, **kwargs): + # Do own init + super(eiscat, self).__init__(*args, **kwargs) diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py new file mode 100644 index 000000000..2201064ad --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -0,0 +1,50 @@ +# +# 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 lib +from base import log + +class magnesium(dboard_manager): + hw_pid = 2 + special_eeprom_addrs = {"special0": "something"} + spi_chipselect = {"0": "lmk", "1": "mykonos", "2": "random"} + spidevs = {} + + def __init__(self, spi_devices, eeprom_data, *args, **kwargs): + # eeprom_data is a tuple (head_dict, raw_data) + if len(spi_devices) != len(self.spi_chipselect): + log.error("Expected {0} spi devices, found {1} spi devices".format(len(spi_devices), len(self.spi_chipselect))) + exit(1) + for spi in spi_devices: + device = self.spi_chipselect.get(spi[-1], None) + if self.chipselect is None: + log.error("Unexpected chipselect {0}".format(spi[-1])) + exit(1) + setattr(self, device, spi) + super(magnesium, self).__init__(*args, **kwargs) + + def init_device(self): + self._device = lib.db.magnesium(self.lmk, self.mykonos, self.random) + + def read_eeprom_v1(self, data): + # magnesium eeprom contains + # nothing + return struct.unpack_from("x", data) + diff --git a/mpm/python/usrp_mpm/dboard_manager/unknown.py b/mpm/python/usrp_mpm/dboard_manager/unknown.py new file mode 100644 index 000000000..f33bacc46 --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/unknown.py @@ -0,0 +1,32 @@ +# +# 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/>. +# +""" +EISCAT rx board implementation module +""" +from base import dboard_manager +from base import lib +from base import log + + +class unknown(dboard_manager): + hw_pid = 0 + special_eeprom_addrs = {} + + def __init__(self, spi_devices, eeprom_data): + self._eeprom = eeprom_data[0] # save eeprom header + # Do own init + super(unknown, self).__init__() diff --git a/mpm/python/usrp_mpm/helper.py b/mpm/python/usrp_mpm/helper.py new file mode 100644 index 000000000..29864124a --- /dev/null +++ b/mpm/python/usrp_mpm/helper.py @@ -0,0 +1,3 @@ + + +class eeprom_helper: diff --git a/mpm/python/usrp_mpm/periph_manager/__init__.py b/mpm/python/usrp_mpm/periph_manager/__init__.py new file mode 100644 index 000000000..96eecf62e --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/__init__.py @@ -0,0 +1,29 @@ +# +# 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/>. +# +""" +periph_manager __init__.py +""" + +# This is where the import magic happens +from .. import libpyusrp_periphs as lib +from .. import dboard_manager +from .. import types + +try: + from n310 import n310 as periph_manager +except ImportError: + raise("Could not import n310") diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py new file mode 100644 index 000000000..f19265a05 --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/base.py @@ -0,0 +1,75 @@ +# +# 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/>. +# +""" +Mboard implementation base class +""" + +import re +import os +from . import lib +from . import types +from . import dboard_manager + + +class periph_manager(object): + # stores discovered device information in dicts + dboards = {} + mboard_if_addrs = {} + mboard_overlays = {} + # this information has to be provided by + # the specific periph_manager implementation + mboard_eeprom_addr = "" + dboard_eeprom_addrs = {} + dboard_spimaster_addrs = {} + + def __init__(self): + # I know my EEPROM address, lets use it + helper = lib.udev_helper.udev_helper() + (self._eeprom_head, self._eeprom_rawdata) = types.eeprom().read_eeprom(helper.get_eeprom(self.mboard_eeprom_addr)) + self._dboard_eeproms = {} + for dboard_slot, eeprom_addr in self.dboard_eeprom_addrs.iteritems(): + spi_devices = [] + # I know EEPROM adresses for my dboard slots + eeprom_data = types.eeprom().read(helper.get_eeprom(eeprom_addr)) + # I know spidev masters on the dboard slots + hw_pid = eeprom_data.get("hw_pid", 0) + if hw_pid in dboards.hw_pids: + spi_devices = helper.get_spidev_nodes(self.dboard_spimaster_addrs.get(dboard_slot)) + dboard = dboards.hw_pids.get(hw_pid, dboards.unknown) + self.dboards.update({dboard_slot: dboard(spi_devices, eeprom_data)}) + + def get_overlays(self): + self.mboard_overlays = [] + for f in os.listdir("/lib/firmware/"): + if f.endswith(".dtbo"): + self.mboard_overlays.append(f.strip(".dtbo")) + + def check_overlay(self): + for f in os.listdir("/sys/kernel/device-tree/overlays/"): + pass #do stuff + + def get_serial(self): + return self._serial + + def load_fpga_image(self, target=None): + pass + + def init_device(self, *args, **kwargs): + # Load FPGA + # Init dboards + pass + diff --git a/mpm/python/usrp_mpm/periph_manager/n310.py b/mpm/python/usrp_mpm/periph_manager/n310.py new file mode 100644 index 000000000..e270387f6 --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/n310.py @@ -0,0 +1,46 @@ +# +# 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/>. +# +""" +N310 implementation module +""" +from base import periph_manager +import struct + + +class n310(periph_manager): + hw_pids = "1" + mboard_eeprom_addr = "e0007000.spi:ec@0:i2c-tunnel" + dboard_eeprom_addrs = {"A": "something", "B": "else"} + dboard_spimaster_addrs = {"A": "something", "B": "else"} + + def __init__(self, eeprom_device, *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) + print(data) + # if header.get("dataversion", 0) == 1: + + def read_eeprom_v1(self, data): + # data_version contains + # 6 bytes mac_addr0 + # 2 bytes pad + # 6 bytes mac_addr1 + # 2 bytes pad + # 6 bytes mac_addr2 + # 2 bytes pad + # 8 bytes serial + return struct.unpack_from("6s 2x 6s 2x 6s 2x 8s", data) diff --git a/mpm/python/usrp_mpm/periphs.py b/mpm/python/usrp_mpm/periphs.py index 3a78f224b..8c00d8f50 100644 --- a/mpm/python/usrp_mpm/periphs.py +++ b/mpm/python/usrp_mpm/periphs.py @@ -19,52 +19,19 @@ """ import libpyusrp_periphs as lib -import re import logging -log = logging.Logger("usrp_mpm.periphs") +import periph_manager +import dboard_manager + +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) + pass + # Moved to periph_manager/base.py __init__ - # 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 + # Next steps implemented in periph_manager/derived class # # 1. Load FPGA image # 2. Use motherboard and daughterboard types to load the FPGA image diff --git a/mpm/python/usrp_mpm/rpc_server.py b/mpm/python/usrp_mpm/rpc_server.py index b092abdf7..a5dda0826 100644 --- a/mpm/python/usrp_mpm/rpc_server.py +++ b/mpm/python/usrp_mpm/rpc_server.py @@ -61,7 +61,10 @@ class ClaimServer(RPCServer): 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", "") + 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) diff --git a/mpm/python/usrp_mpm/types.py b/mpm/python/usrp_mpm/types.py index bd7a874a8..31252e0b8 100644 --- a/mpm/python/usrp_mpm/types.py +++ b/mpm/python/usrp_mpm/types.py @@ -17,16 +17,18 @@ """ MPM types """ +import ctypes from multiprocessing import Value from multiprocessing import Array from multiprocessing import Lock -import ctypes +import struct MPM_RPC_PORT = 49601 MPM_DISCOVERY_PORT = 49600 MPM_DISCOVERY_MESSAGE = "MPM-DISC" + class graceful_exit(Exception): pass @@ -36,3 +38,30 @@ class shared_state: 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 + + +class eeprom(object): + # eeprom_header contains: + # 4 bytes magic + # 4 bytes CRC + # 2 bytes data_version + # 2 bytes hw_pid + # 2 bytes hw_rev + # 2 bytes pad + # + # 16 bytes in total + eeprom_header = struct.Struct("I I H H H 2x") + + def read_eeprom(self, nvmem_path): + with open(nvmem_path, "rb") as f: + header = f.read(16) + data = f.read(240) + header = self.eeprom_header.unpack(header) + header = { + "magic": header[0], + "crc": header[1], + "data_version": header[2], + "hw_pid": header[3], + "hw_rev": header[4], + } + return (header, data) |