From 37ebaa6ad84e90c7d1d0d1133af008e9970a333f Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 13 Feb 2017 10:19:43 -0800 Subject: n230: Fold in module fka usrp3_fw_ctrl_iface --- host/lib/usrp/n230/CMakeLists.txt | 1 + host/lib/usrp/n230/fw_comm_protocol.h | 102 +++++++++++ host/lib/usrp/n230/n230_fw_ctrl_iface.cpp | 245 +++++++++++++++++++++++++++ host/lib/usrp/n230/n230_fw_ctrl_iface.hpp | 72 ++++++++ host/lib/usrp/n230/n230_impl.cpp | 9 +- host/lib/usrp/n230/n230_resource_manager.cpp | 8 +- host/lib/usrp/n230/n230_resource_manager.hpp | 8 +- 7 files changed, 432 insertions(+), 13 deletions(-) create mode 100644 host/lib/usrp/n230/fw_comm_protocol.h create mode 100644 host/lib/usrp/n230/n230_fw_ctrl_iface.cpp create mode 100644 host/lib/usrp/n230/n230_fw_ctrl_iface.hpp (limited to 'host/lib/usrp/n230') diff --git a/host/lib/usrp/n230/CMakeLists.txt b/host/lib/usrp/n230/CMakeLists.txt index 9eaccffba..8bed1f26d 100644 --- a/host/lib/usrp/n230/CMakeLists.txt +++ b/host/lib/usrp/n230/CMakeLists.txt @@ -33,5 +33,6 @@ IF(ENABLE_N230) ${CMAKE_CURRENT_SOURCE_DIR}/n230_frontend_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/n230_uart.cpp ${CMAKE_CURRENT_SOURCE_DIR}/n230_image_loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/n230_fw_ctrl_iface.cpp ) ENDIF(ENABLE_N230) diff --git a/host/lib/usrp/n230/fw_comm_protocol.h b/host/lib/usrp/n230/fw_comm_protocol.h new file mode 100644 index 000000000..14adb33a9 --- /dev/null +++ b/host/lib/usrp/n230/fw_comm_protocol.h @@ -0,0 +1,102 @@ +// +// Copyright 2014 Ettus Research LLC +// +// 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 . +// + +#ifndef INCLUDED_FW_COMM_PROTOCOL +#define INCLUDED_FW_COMM_PROTOCOL + +#include +#ifndef __cplusplus +#include +#endif + +/*! + * Structs and constants for communication between firmware and host. + * This header is shared by the firmware and host code. + * Therefore, this header may only contain valid C code. + */ +#ifdef __cplusplus +extern "C" { +#endif + +#define FW_COMM_PROTOCOL_SIGNATURE 0xACE3 +#define FW_COMM_PROTOCOL_VERSION 0 +#define FW_COMM_MAX_DATA_WORDS 16 +#define FW_COMM_PROTOCOL_MTU 256 + +#define FW_COMM_FLAGS_ACK 0x00000001 +#define FW_COMM_FLAGS_CMD_MASK 0x00000FF0 +#define FW_COMM_FLAGS_ERROR_MASK 0xFF000000 + +#define FW_COMM_CMD_ECHO 0x00000000 +#define FW_COMM_CMD_POKE32 0x00000010 +#define FW_COMM_CMD_PEEK32 0x00000020 +#define FW_COMM_CMD_BLOCK_POKE32 0x00000030 +#define FW_COMM_CMD_BLOCK_PEEK32 0x00000040 + +#define FW_COMM_ERR_PKT_ERROR 0x80000000 +#define FW_COMM_ERR_CMD_ERROR 0x40000000 +#define FW_COMM_ERR_SIZE_ERROR 0x20000000 + +#define FW_COMM_GENERATE_ID(prod) ((((uint32_t) FW_COMM_PROTOCOL_SIGNATURE) << 0) | \ + (((uint32_t) prod) << 16) | \ + (((uint32_t) FW_COMM_PROTOCOL_VERSION) << 24)) + +#define FW_COMM_GET_PROTOCOL_SIG(id) ((uint16_t)(id & 0xFFFF)) +#define FW_COMM_GET_PRODUCT_ID(id) ((uint8_t)(id >> 16)) +#define FW_COMM_GET_PROTOCOL_VER(id) ((uint8_t)(id >> 24)) + +typedef struct +{ + uint32_t id; //Protocol and device identifier + uint32_t flags; //Holds commands and ack messages + uint32_t sequence; //Sequence number (specific to FW communication transactions) + uint32_t data_words; //Number of data words in payload + uint32_t addr; //Address field for the command in flags + uint32_t data[FW_COMM_MAX_DATA_WORDS]; //Data field for the command in flags +} fw_comm_pkt_t; + +#ifdef __cplusplus +} //extern "C" +#endif + +// The following definitions are only useful in firmware. Exclude in host code. +#ifndef __cplusplus + +typedef void (*poke32_func)(const uint32_t addr, const uint32_t data); +typedef uint32_t (*peek32_func)(const uint32_t addr); + +/*! + * Process a firmware communication packet and compute a response. + * Args: + * - (in) request: Pointer to the request struct + * - (out) response: Pointer to the response struct + * - (in) product_id: The 8-bit usrp3 specific product ID (for request filtering) + * - (func) poke_callback, peek_callback: Callback functions for a single peek/poke + * - return value: Send a response packet + */ +bool process_fw_comm_protocol_pkt( + const fw_comm_pkt_t* request, + fw_comm_pkt_t* response, + uint8_t product_id, + uint32_t iface_id, + poke32_func poke_callback, + peek32_func peek_callback +); + +#endif //ifdef __cplusplus + +#endif /* INCLUDED_FW_COMM_PROTOCOL */ diff --git a/host/lib/usrp/n230/n230_fw_ctrl_iface.cpp b/host/lib/usrp/n230/n230_fw_ctrl_iface.cpp new file mode 100644 index 000000000..68fad3035 --- /dev/null +++ b/host/lib/usrp/n230/n230_fw_ctrl_iface.cpp @@ -0,0 +1,245 @@ +// +// Copyright 2013 Ettus Research LLC +// +// 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 . +// + +#include "n230_fw_ctrl_iface.hpp" + +#include +#include +#include +#include +#include //used for htonl and ntohl +#include "fw_comm_protocol.h" + +namespace uhd { namespace usrp { namespace n230 { + +//---------------------------------------------------------- +// Factory method +//---------------------------------------------------------- +uhd::wb_iface::sptr n230_fw_ctrl_iface::make( + uhd::transport::udp_simple::sptr udp_xport, + const uint16_t product_id, + const bool verbose) +{ + return wb_iface::sptr(new n230_fw_ctrl_iface(udp_xport, product_id, verbose)); +} + +//---------------------------------------------------------- +// udp_fw_ctrl_iface +//---------------------------------------------------------- + +n230_fw_ctrl_iface::n230_fw_ctrl_iface( + uhd::transport::udp_simple::sptr udp_xport, + const uint16_t product_id, + const bool verbose) : + _product_id(product_id), _verbose(verbose), _udp_xport(udp_xport), + _seq_num(0) +{ + flush(); + peek32(0); +} + +n230_fw_ctrl_iface::~n230_fw_ctrl_iface() +{ + flush(); +} + +void n230_fw_ctrl_iface::flush() +{ + boost::mutex::scoped_lock lock(_mutex); + _flush(); +} + +void n230_fw_ctrl_iface::poke32(const wb_addr_type addr, const uint32_t data) +{ + boost::mutex::scoped_lock lock(_mutex); + + for (size_t i = 1; i <= NUM_RETRIES; i++) { + try { + _poke32(addr, data); + return; + } catch(const std::exception &ex) { + const std::string error_msg = str(boost::format( + "udp fw poke32 failure #%u\n%s") % i % ex.what()); + if (_verbose) UHD_MSG(warning) << error_msg << std::endl; + if (i == NUM_RETRIES) throw uhd::io_error(error_msg); + } + } +} + +uint32_t n230_fw_ctrl_iface::peek32(const wb_addr_type addr) +{ + boost::mutex::scoped_lock lock(_mutex); + + for (size_t i = 1; i <= NUM_RETRIES; i++) { + try { + return _peek32(addr); + } catch(const std::exception &ex) { + const std::string error_msg = str(boost::format( + "udp fw peek32 failure #%u\n%s") % i % ex.what()); + if (_verbose) UHD_MSG(warning) << error_msg << std::endl; + if (i == NUM_RETRIES) throw uhd::io_error(error_msg); + } + } + return 0; +} + +void n230_fw_ctrl_iface::_poke32(const wb_addr_type addr, const uint32_t data) +{ + //Load request struct + fw_comm_pkt_t request; + request.id = uhd::htonx(FW_COMM_GENERATE_ID(_product_id)); + request.flags = uhd::htonx(FW_COMM_FLAGS_ACK | FW_COMM_CMD_POKE32); + request.sequence = uhd::htonx(_seq_num++); + request.addr = uhd::htonx(addr); + request.data_words = 1; + request.data[0] = uhd::htonx(data); + + //Send request + _flush(); + _udp_xport->send(boost::asio::buffer(&request, sizeof(request))); + + //Recv reply + fw_comm_pkt_t reply; + const size_t nbytes = _udp_xport->recv(boost::asio::buffer(&reply, sizeof(reply)), 1.0); + if (nbytes == 0) throw uhd::io_error("udp fw poke32 - reply timed out"); + + //Sanity checks + const size_t flags = uhd::ntohx(reply.flags); + UHD_ASSERT_THROW(nbytes == sizeof(reply)); + UHD_ASSERT_THROW(not (flags & FW_COMM_FLAGS_ERROR_MASK)); + UHD_ASSERT_THROW(flags & FW_COMM_CMD_POKE32); + UHD_ASSERT_THROW(flags & FW_COMM_FLAGS_ACK); + UHD_ASSERT_THROW(reply.sequence == request.sequence); + UHD_ASSERT_THROW(reply.addr == request.addr); + UHD_ASSERT_THROW(reply.data[0] == request.data[0]); +} + +uint32_t n230_fw_ctrl_iface::_peek32(const wb_addr_type addr) +{ + //Load request struct + fw_comm_pkt_t request; + request.id = uhd::htonx(FW_COMM_GENERATE_ID(_product_id)); + request.flags = uhd::htonx(FW_COMM_FLAGS_ACK | FW_COMM_CMD_PEEK32); + request.sequence = uhd::htonx(_seq_num++); + request.addr = uhd::htonx(addr); + request.data_words = 1; + request.data[0] = 0; + + //Send request + _flush(); + _udp_xport->send(boost::asio::buffer(&request, sizeof(request))); + + //Recv reply + fw_comm_pkt_t reply; + const size_t nbytes = _udp_xport->recv(boost::asio::buffer(&reply, sizeof(reply)), 1.0); + if (nbytes == 0) throw uhd::io_error("udp fw peek32 - reply timed out"); + + //Sanity checks + const size_t flags = uhd::ntohx(reply.flags); + UHD_ASSERT_THROW(nbytes == sizeof(reply)); + UHD_ASSERT_THROW(not (flags & FW_COMM_FLAGS_ERROR_MASK)); + UHD_ASSERT_THROW(flags & FW_COMM_CMD_PEEK32); + UHD_ASSERT_THROW(flags & FW_COMM_FLAGS_ACK); + UHD_ASSERT_THROW(reply.sequence == request.sequence); + UHD_ASSERT_THROW(reply.addr == request.addr); + + //return result! + return uhd::ntohx(reply.data[0]); +} + +void n230_fw_ctrl_iface::_flush(void) +{ + char buff[FW_COMM_PROTOCOL_MTU] = {}; + while (_udp_xport->recv(boost::asio::buffer(buff), 0.0)) { + /*NOP*/ + } +} + +std::vector n230_fw_ctrl_iface::discover_devices( + const std::string& addr_hint, const std::string& port, + uint16_t product_id) +{ + std::vector addrs; + + //Create a UDP transport to communicate: + //Some devices will cause a throw when opened for a broadcast address. + //We print and recover so the caller can loop through all bcast addrs. + uhd::transport::udp_simple::sptr udp_bcast_xport; + try { + udp_bcast_xport = uhd::transport::udp_simple::make_broadcast(addr_hint, port); + } catch(const std::exception &e) { + UHD_MSG(error) << boost::format("Cannot open UDP transport on %s for discovery\n%s") + % addr_hint % e.what() << std::endl; + return addrs; + } + + //Send dummy request + fw_comm_pkt_t request; + request.id = uhd::htonx(FW_COMM_GENERATE_ID(product_id)); + request.flags = uhd::htonx(FW_COMM_FLAGS_ACK|FW_COMM_CMD_ECHO); + request.sequence = uhd::htonx(std::rand()); + udp_bcast_xport->send(boost::asio::buffer(&request, sizeof(request))); + + //loop for replies until timeout + while (true) { + char buff[FW_COMM_PROTOCOL_MTU] = {}; + const size_t nbytes = udp_bcast_xport->recv(boost::asio::buffer(buff), 0.050); + if (nbytes != sizeof(fw_comm_pkt_t)) break; //No more responses or responses are invalid + + const fw_comm_pkt_t *reply = (const fw_comm_pkt_t *)buff; + if (request.id == reply->id && + request.flags == reply->flags && + request.sequence == reply->sequence) + { + addrs.push_back(udp_bcast_xport->get_recv_addr()); + } + } + + return addrs; +} + +uint32_t n230_fw_ctrl_iface::get_iface_id( + const std::string& addr, const std::string& port, + uint16_t product_id) +{ + uhd::transport::udp_simple::sptr udp_xport = + uhd::transport::udp_simple::make_connected(addr, port); + + //Send dummy request + fw_comm_pkt_t request; + request.id = uhd::htonx(FW_COMM_GENERATE_ID(product_id)); + request.flags = uhd::htonx(FW_COMM_FLAGS_ACK|FW_COMM_CMD_ECHO); + request.sequence = uhd::htonx(std::rand()); + udp_xport->send(boost::asio::buffer(&request, sizeof(request))); + + //loop for replies until timeout + char buff[FW_COMM_PROTOCOL_MTU] = {}; + const size_t nbytes = udp_xport->recv(boost::asio::buffer(buff), 1.0); + + const fw_comm_pkt_t *reply = (const fw_comm_pkt_t *)buff; + if (nbytes > 0 && + request.id == reply->id && + request.flags == reply->flags && + request.sequence == reply->sequence) + { + return uhd::ntohx(reply->data[0]); + } else { + throw uhd::io_error("udp get_iface_id - bad response"); + } +} + +}}} //namespace diff --git a/host/lib/usrp/n230/n230_fw_ctrl_iface.hpp b/host/lib/usrp/n230/n230_fw_ctrl_iface.hpp new file mode 100644 index 000000000..675c843b3 --- /dev/null +++ b/host/lib/usrp/n230/n230_fw_ctrl_iface.hpp @@ -0,0 +1,72 @@ +// +// Copyright 2014 Ettus Research LLC +// +// 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 . +// + +#ifndef INCLUDED_LIBUHD_USRP_N230_UDP_FW_CTRL_IFACE_HPP +#define INCLUDED_LIBUHD_USRP_N230_UDP_FW_CTRL_IFACE_HPP + +#include +#include +#include +#include + +namespace uhd { namespace usrp { namespace n230 { + +class n230_fw_ctrl_iface : public uhd::wb_iface +{ +public: + n230_fw_ctrl_iface( + uhd::transport::udp_simple::sptr udp_xport, + const uint16_t product_id, + const bool verbose); + virtual ~n230_fw_ctrl_iface(); + + // -- uhd::wb_iface -- + void poke32(const wb_addr_type addr, const uint32_t data); + uint32_t peek32(const wb_addr_type addr); + void flush(); + + static uhd::wb_iface::sptr make( + uhd::transport::udp_simple::sptr udp_xport, + const uint16_t product_id, + const bool verbose = true); + // -- uhd::wb_iface -- + + static std::vector discover_devices( + const std::string& addr_hint, const std::string& port, + uint16_t product_id); + + static uint32_t get_iface_id( + const std::string& addr, const std::string& port, + uint16_t product_id); + +private: + void _poke32(const wb_addr_type addr, const uint32_t data); + uint32_t _peek32(const wb_addr_type addr); + void _flush(void); + + const uint16_t _product_id; + const bool _verbose; + uhd::transport::udp_simple::sptr _udp_xport; + uint32_t _seq_num; + boost::mutex _mutex; + + static const size_t NUM_RETRIES = 3; +}; + +}}} //namespace + +#endif // INCLUDED_LIBUHD_USRP_N230_UDP_FW_CTRL_IFACE_HPP diff --git a/host/lib/usrp/n230/n230_impl.cpp b/host/lib/usrp/n230/n230_impl.cpp index 325b90575..817868ef0 100644 --- a/host/lib/usrp/n230/n230_impl.cpp +++ b/host/lib/usrp/n230/n230_impl.cpp @@ -17,7 +17,7 @@ #include "n230_impl.hpp" -#include "usrp3_fw_ctrl_iface.hpp" +#include "n230_fw_ctrl_iface.hpp" #include "validate_subdev_spec.hpp" #include #include @@ -41,7 +41,6 @@ #include //used for htonl and ntohl #include -#include "../common/fw_comm_protocol.h" #include "n230_defaults.h" #include "n230_fpga_defs.h" #include "n230_fw_defs.h" @@ -115,7 +114,7 @@ uhd::device_addrs_t n230_impl::n230_find(const uhd::device_addr_t &multi_dev_hin } std::vector discovered_addrs = - usrp3::usrp3_fw_ctrl_iface::discover_devices( + n230_fw_ctrl_iface::discover_devices( hint["addr"], BOOST_STRINGIZE(N230_FW_COMMS_UDP_PORT), N230_FW_PRODUCT_ID); for(const std::string& addr: discovered_addrs) @@ -135,10 +134,10 @@ uhd::device_addrs_t n230_impl::n230_find(const uhd::device_addr_t &multi_dev_hin //connected communication can fail. Retry the following call to allow //the stack to update size_t first_conn_retries = 10; - usrp3::usrp3_fw_ctrl_iface::sptr fw_ctrl; + n230_fw_ctrl_iface::sptr fw_ctrl; while (first_conn_retries > 0) { try { - fw_ctrl = usrp3::usrp3_fw_ctrl_iface::make(ctrl_xport, N230_FW_PRODUCT_ID, false /*verbose*/); + fw_ctrl = n230_fw_ctrl_iface::make(ctrl_xport, N230_FW_PRODUCT_ID, false /*verbose*/); break; } catch (uhd::io_error& ex) { boost::this_thread::sleep(boost::posix_time::milliseconds(500)); diff --git a/host/lib/usrp/n230/n230_resource_manager.cpp b/host/lib/usrp/n230/n230_resource_manager.cpp index 08a98d245..c5617bbf7 100644 --- a/host/lib/usrp/n230/n230_resource_manager.cpp +++ b/host/lib/usrp/n230/n230_resource_manager.cpp @@ -17,7 +17,7 @@ #include "n230_resource_manager.hpp" -#include "usrp3_fw_ctrl_iface.hpp" +#include "n230_fw_ctrl_iface.hpp" #include #include #include @@ -91,7 +91,7 @@ n230_resource_manager::n230_resource_manager( uint32_t iface_id = 0xFFFFFFFF; try { - iface_id = usrp3::usrp3_fw_ctrl_iface::get_iface_id( + iface_id = n230::n230_fw_ctrl_iface::get_iface_id( conn_iface.ip_addr, BOOST_STRINGIZE(N230_FW_COMMS_UDP_PORT), N230_FW_PRODUCT_ID); } catch (uhd::io_error&) { throw uhd::io_error(str(boost::format( @@ -118,7 +118,7 @@ n230_resource_manager::n230_resource_manager( } //Create firmware communication interface - _fw_ctrl = usrp3::usrp3_fw_ctrl_iface::make( + _fw_ctrl = n230::n230_fw_ctrl_iface::make( transport::udp_simple::make_connected( _get_conn(PRI_ETH).ip_addr, BOOST_STRINGIZE(N230_FW_COMMS_UDP_PORT)), N230_FW_PRODUCT_ID); if (_fw_ctrl.get() == NULL) { @@ -276,7 +276,7 @@ transport::zero_copy_if::sptr n230_resource_manager::create_transport( return xport; } -bool n230_resource_manager::is_device_claimed(uhd::usrp::usrp3::usrp3_fw_ctrl_iface::sptr fw_ctrl) +bool n230_resource_manager::is_device_claimed(n230_fw_ctrl_iface::sptr fw_ctrl) { boost::mutex::scoped_lock(_claimer_mutex); diff --git a/host/lib/usrp/n230/n230_resource_manager.hpp b/host/lib/usrp/n230/n230_resource_manager.hpp index 180f4f437..6da3b9035 100644 --- a/host/lib/usrp/n230/n230_resource_manager.hpp +++ b/host/lib/usrp/n230/n230_resource_manager.hpp @@ -37,7 +37,7 @@ #include #include -#include "usrp3_fw_ctrl_iface.hpp" +#include "n230_fw_ctrl_iface.hpp" #include "n230_clk_pps_ctrl.hpp" #include "n230_cores.hpp" #include "n230_fpga_defs.h" @@ -98,7 +98,7 @@ public: //Methods n230_resource_manager(const std::vector ip_addrs, const bool safe_mode); virtual ~n230_resource_manager(); - static bool is_device_claimed(uhd::usrp::usrp3::usrp3_fw_ctrl_iface::sptr fw_ctrl); + static bool is_device_claimed(n230_fw_ctrl_iface::sptr fw_ctrl); inline bool is_device_claimed() { if (_fw_ctrl.get()) { @@ -276,12 +276,12 @@ private: ver_info_t _fpga_version; //Firmware register interface - uhd::usrp::usrp3::usrp3_fw_ctrl_iface::sptr _fw_ctrl; + n230_fw_ctrl_iface::sptr _fw_ctrl; uhd::task::sptr _claimer_task; static boost::mutex _claimer_mutex; //All claims and checks in this process are serialized //Transport - uint8_t _last_host_enpoint; + uint8_t _last_host_enpoint; //Radio settings interface radio_ctrl_core_3000::sptr _core_ctrl; -- cgit v1.2.3