diff options
30 files changed, 108 insertions, 2480 deletions
diff --git a/.gitmodules b/.gitmodules index 473a21289..c85c089b3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "fpga-src"] path = fpga-src url = https://github.com/EttusResearch/fpga.git - branch = maint + branch = master diff --git a/host/cmake/Modules/UHDConfigVersion.cmake.in b/host/cmake/Modules/UHDConfigVersion.cmake.in index 549798324..c792b5bf8 100644 --- a/host/cmake/Modules/UHDConfigVersion.cmake.in +++ b/host/cmake/Modules/UHDConfigVersion.cmake.in @@ -29,13 +29,13 @@ set(ENV{UHD_CONFIG_VERSION_USED} TRUE) # version values as set in cmake/Modules/UHDVersion.cmake, placed # statically in here to avoid using Python all over again. -SET(MAJOR_VERSION @TRIMMED_VERSION_MAJOR@) -SET(API_VERSION @TRIMMED_VERSION_API@) -SET(ABI_VERSION @TRIMMED_VERSION_ABI@) -SET(PATCH_VERSION @TRIMMED_VERSION_PATCH@) +SET(MAJOR_VERSION @UHD_VERSION_MAJOR@) +SET(API_VERSION @UHD_VERSION_API@) +SET(ABI_VERSION @UHD_VERSION_ABI@) +SET(PATCH_VERSION @UHD_VERSION_PATCH@) SET(DEVEL_VERSION @UHD_VERSION_DEVEL@) -SET(PACKAGE_VERSION @TRIMMED_UHD_VERSION@) +SET(PACKAGE_VERSION @UHD_VERSION@) SET(ENV{UHD_PACKAGE_VERSION} ${PACKAGE_VERSION}) # There is a bug in CMake whereby calling "find_package(FOO)" within @@ -175,4 +175,4 @@ IF(${PACKAGE_FIND_VERSION} VERSION_EQUAL ${PACKAGE_VERSION}) ENDIF() # Undo our patch-version-number hack -SET(PACKAGE_VERSION @TRIMMED_UHD_VERSION@) +SET(PACKAGE_VERSION @UHD_VERSION@) diff --git a/host/cmake/Modules/UHDGlobalDefs.cmake b/host/cmake/Modules/UHDGlobalDefs.cmake index 167861402..f237126a6 100644 --- a/host/cmake/Modules/UHDGlobalDefs.cmake +++ b/host/cmake/Modules/UHDGlobalDefs.cmake @@ -24,9 +24,9 @@ CHECK_CXX_SYMBOL_EXISTS(log2 cmath HAVE_LOG2) ## Macros for the version number IF(UHD_VERSION_DEVEL) - MATH(EXPR UHD_VERSION_ADDED "1000000 * ${TRIMMED_VERSION_MAJOR} + 10000 * ${TRIMMED_VERSION_API} + 100 * ${TRIMMED_VERSION_ABI} + 99") + MATH(EXPR UHD_VERSION_ADDED "1000000 * ${UHD_VERSION_MAJOR} + 10000 * ${UHD_VERSION_API} + 100 * ${UHD_VERSION_ABI} + 99") ELSE() - MATH(EXPR UHD_VERSION_ADDED "1000000 * ${TRIMMED_VERSION_MAJOR} + 10000 * ${TRIMMED_VERSION_API} + 100 * ${TRIMMED_VERSION_ABI} + ${TRIMMED_VERSION_PATCH}") + MATH(EXPR UHD_VERSION_ADDED "1000000 * ${UHD_VERSION_MAJOR} + 10000 * ${UHD_VERSION_API} + 100 * ${UHD_VERSION_ABI} + ${UHD_VERSION_PATCH}") ENDIF(UHD_VERSION_DEVEL) ADD_DEFINITIONS(-DUHD_VERSION=${UHD_VERSION_ADDED}) diff --git a/host/cmake/Modules/UHDPackage.cmake b/host/cmake/Modules/UHDPackage.cmake index 3b8b69ab5..138abacb9 100644 --- a/host/cmake/Modules/UHDPackage.cmake +++ b/host/cmake/Modules/UHDPackage.cmake @@ -55,13 +55,12 @@ ENDIF() ######################################################################## # Setup package file name ######################################################################## - IF(DEBIAN AND LIBUHD_PKG) - SET(CPACK_PACKAGE_FILE_NAME "libuhd${UHD_VERSION_MAJOR}_${TRIMMED_UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") + SET(CPACK_PACKAGE_FILE_NAME "libuhd${UHD_VERSION_MAJOR}_${UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") ELSEIF(DEBIAN AND LIBUHDDEV_PKG) - SET(CPACK_PACKAGE_FILE_NAME "libuhd-dev_${TRIMMED_UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") + SET(CPACK_PACKAGE_FILE_NAME "libuhd-dev_${UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") ELSEIF(DEBIAN AND UHDHOST_PKG) - SET(CPACK_PACKAGE_FILE_NAME "uhd-host_${TRIMMED_UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") + SET(CPACK_PACKAGE_FILE_NAME "uhd-host_${UHD_VERSION}_${CMAKE_SYSTEM_PROCESSOR}" CACHE INTERNAL "") ELSE() IF(DEBIAN OR REDHAT) FIND_PROGRAM(LSB_RELEASE_EXECUTABLE lsb_release) @@ -124,7 +123,7 @@ SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) # Setup CPack Source ######################################################################## -SET(CPACK_SOURCE_PACKAGE_FILE_NAME "uhd-${TRIMMED_UHD_VERSION}" CACHE INTERNAL "") +SET(CPACK_SOURCE_PACKAGE_FILE_NAME "uhd-${UHD_VERSION}" CACHE INTERNAL "") SET(CPACK_SOURCE_IGNORE_FILES "\\\\.git*;\\\\.swp$") ######################################################################## diff --git a/host/cmake/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake index 26dbfbb06..0e8064ff3 100644 --- a/host/cmake/Modules/UHDVersion.cmake +++ b/host/cmake/Modules/UHDVersion.cmake @@ -27,11 +27,11 @@ FIND_PACKAGE(Git QUIET) # - Increment patch for bugfixes and docs # - set UHD_VERSION_DEVEL to true for master and development branches ######################################################################## -SET(UHD_VERSION_MAJOR 003) -SET(UHD_VERSION_API 010) -SET(UHD_VERSION_ABI 001) -SET(UHD_VERSION_PATCH 000) -SET(UHD_VERSION_DEVEL FALSE) +SET(UHD_VERSION_MAJOR 3) +SET(UHD_VERSION_API 11) +SET(UHD_VERSION_ABI 0) +SET(UHD_VERSION_PATCH git) +SET(UHD_VERSION_DEVEL TRUE) ######################################################################## # If we're on a development branch, we skip the patch version @@ -74,28 +74,6 @@ IF(GIT_FOUND) ENDIF(GIT_FOUND) ######################################################################## -# Set up trimmed version numbers for DLL resource files and packages -######################################################################## -FUNCTION(DEPAD_NUM input_num output_num) - EXECUTE_PROCESS( - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${PYTHON_EXECUTABLE} -c "print(int('${input_num}'))" - OUTPUT_VARIABLE depadded_num OUTPUT_STRIP_TRAILING_WHITESPACE - ) - SET(${output_num} ${depadded_num} PARENT_SCOPE) -ENDFUNCTION(DEPAD_NUM) - -DEPAD_NUM(${UHD_VERSION_MAJOR} TRIMMED_VERSION_MAJOR) -DEPAD_NUM(${UHD_VERSION_API} TRIMMED_VERSION_API) -DEPAD_NUM(${UHD_VERSION_ABI} TRIMMED_VERSION_ABI) -IF(UHD_VERSION_DEVEL) - SET(TRIMMED_VERSION_PATCH ${UHD_VERSION_PATCH}) -ELSE(UHD_VERSION_DEVEL) - DEPAD_NUM(${UHD_VERSION_PATCH} TRIMMED_VERSION_PATCH) -ENDIF(UHD_VERSION_DEVEL) -SET(TRIMMED_UHD_VERSION "${TRIMMED_VERSION_MAJOR}.${TRIMMED_VERSION_API}.${TRIMMED_VERSION_ABI}.${TRIMMED_VERSION_PATCH}") - -######################################################################## # Version information discovery through git log ######################################################################## diff --git a/host/include/config.h.in b/host/include/config.h.in index 8931d6580..b1958ae42 100644 --- a/host/include/config.h.in +++ b/host/include/config.h.in @@ -18,9 +18,9 @@ #cmakedefine HAVE_LOG2 /* Version macros */ -#cmakedefine UHD_VERSION_MAJOR ${TRIMMED_VERSION_MAJOR} -#cmakedefine UHD_VERSION_API ${TRIMMED_VERSION_API} -#cmakedefine UHD_VERSION_ABI ${TRIMMED_VERSION_ABI} -#cmakedefine UHD_VERSION_PATCH ${TRIMMED_VERSION_PATCH} +#cmakedefine UHD_VERSION_MAJOR ${UHD_VERSION_MAJOR} +#cmakedefine UHD_VERSION_API ${UHD_VERSION_API} +#cmakedefine UHD_VERSION_ABI ${UHD_VERSION_ABI} +#cmakedefine UHD_VERSION_PATCH ${UHD_VERSION_PATCH} #cmakedefine ENABLE_USB #cmakedefine UHD_VERSION @UHD_VERSION_ADDED@ diff --git a/host/include/uhd/rfnoc/block_ctrl_base.hpp b/host/include/uhd/rfnoc/block_ctrl_base.hpp index 725f0d966..724e155bb 100644 --- a/host/include/uhd/rfnoc/block_ctrl_base.hpp +++ b/host/include/uhd/rfnoc/block_ctrl_base.hpp @@ -46,7 +46,6 @@ struct make_args_t { make_args_t(const std::string &key="") : device_index(0), - is_big_endian(true), block_name(""), block_key(key) {} @@ -61,7 +60,6 @@ struct make_args_t // property tree is /mboards/0, pass a subtree starting at /mboards/0 // to the constructor. uhd::property_tree::sptr tree; - bool is_big_endian; //! The name of the block as it will be addressed std::string block_name; //! The key of the block, i.e. how it was registered @@ -391,9 +389,6 @@ protected: //! Root node of this block's properties uhd::fs_path _root_path; - //! Endianness of underlying transport (for data transport) - bool _transport_is_big_endian; - //! Block definition (stores info about the block such as ports) blockdef::sptr _block_def; diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp index 5ea8e8f41..f1471549e 100644 --- a/host/include/uhd/types/sid.hpp +++ b/host/include/uhd/types/sid.hpp @@ -1,5 +1,5 @@ // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-2016 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 @@ -19,9 +19,8 @@ #define INCLUDED_UHD_TYPES_SID_HPP #include <uhd/config.hpp> -#include <stdint.h> -#include <boost/shared_ptr.hpp> #include <iostream> +#include <stdint.h> namespace uhd { /*! @@ -99,47 +98,47 @@ namespace uhd { // Getters // //! Alias for get_sid() - UHD_INLINE uint32_t get() const { return get_sid(); }; + inline uint32_t get() const { return get_sid(); }; //! Returns a 32-Bit representation of the SID if set, or zero otherwise. - UHD_INLINE uint32_t get_sid() const { return _set ? _sid : 0; }; + inline uint32_t get_sid() const { return _set ? _sid : 0; }; //! Return the 16-bit source address of this SID - UHD_INLINE uint32_t get_src() const { + inline uint32_t get_src() const { return (_sid >> 16) & 0xFFFF; } //! Return the 16-bit destination address of this SID - UHD_INLINE uint32_t get_dst() const { + inline uint32_t get_dst() const { return _sid & 0xFFFF; } //! Return 8-bit address of the source - UHD_INLINE uint32_t get_src_addr() const { + inline uint32_t get_src_addr() const { return (get_src() >> 8) & 0xFF; } //! Return endpoint of the source - UHD_INLINE uint32_t get_src_endpoint() const { + inline uint32_t get_src_endpoint() const { return get_src() & 0xFF; } //! Return crossbar port of the source - UHD_INLINE uint32_t get_src_xbarport() const { + inline uint32_t get_src_xbarport() const { return (get_src_endpoint() >> 4) & 0xF; } //! Return block port of the source - UHD_INLINE uint32_t get_src_blockport() const { + inline uint32_t get_src_blockport() const { return (get_src_endpoint()) & 0xF; } //! Return 8-bit address of the destination - UHD_INLINE uint32_t get_dst_addr() const { + inline uint32_t get_dst_addr() const { return (get_dst() >> 8) & 0xFF; } //! Return endpoint of the destination - UHD_INLINE uint32_t get_dst_endpoint() const { + inline uint32_t get_dst_endpoint() const { return get_dst() & 0xFF; } //! Return crossbar port of the source - UHD_INLINE uint32_t get_dst_xbarport() const { + inline uint32_t get_dst_xbarport() const { return (get_dst_endpoint() >> 4) & 0xF; } //! Return block port of the source - UHD_INLINE uint32_t get_dst_blockport() const { + inline uint32_t get_dst_blockport() const { return (get_dst_endpoint()) & 0xF; } @@ -168,14 +167,14 @@ namespace uhd { // Manipulators //! Swaps dst and src address and returns the new SID. - sid_t reversed(); + sid_t reversed() const; - //! Swaps dst and src in-place. + //! Swaps dst and src in-place. This modifies the current SID. void reverse(); // Overloaded operators - sid_t operator = (uint32_t new_sid) { + sid_t operator = (const uint32_t new_sid) { set_sid(new_sid); return *this; } @@ -185,6 +184,11 @@ namespace uhd { return *this; } + sid_t operator = (const sid_t &sid) { + set_sid(sid.get_sid()); + return *this; + } + sid_t operator = (const std::string &sid_str) { set_from_str(sid_str); return *this; @@ -222,7 +226,7 @@ namespace uhd { }; //! Stream output operator. Honors std::ios::hex. - UHD_INLINE std::ostream& operator<< (std::ostream& out, const sid_t &sid) { + inline std::ostream& operator<< (std::ostream& out, const sid_t &sid) { std::ios_base::fmtflags ff = out.flags(); if (ff & std::ios::hex) { out << sid.to_pp_string_hex(); diff --git a/host/include/uhd/utils/atomic.hpp b/host/include/uhd/utils/atomic.hpp index ec4d3e0a2..f37fb4395 100644 --- a/host/include/uhd/utils/atomic.hpp +++ b/host/include/uhd/utils/atomic.hpp @@ -68,76 +68,6 @@ namespace uhd{ }; /*! - * A reusable barrier to sync multiple threads. - * All threads spin on wait() until count is reset. - */ - class UHD_API reusable_barrier{ - public: - - reusable_barrier():_size (0) {} - - reusable_barrier(const size_t size):_size(size) {} - - //! Resize the barrier for N threads - void resize(const size_t size){ - _size = size; - } - - /*! - * Force the barrier wait to throw a boost::thread_interrupted - * The threads were not getting the interruption_point on windows. - */ - void interrupt(void) - { - _done.inc(); - } - - //! Wait on the barrier condition - UHD_INLINE void wait(void) - { - if (_size == 1) return; - - //entry barrier with condition variable - _entry_counter.inc(); - _entry_counter.cas(0, _size); - boost::mutex::scoped_lock lock(_mutex); - while (_entry_counter.read() != 0) - { - this->check_interrupt(); - _cond.timed_wait(lock, boost::posix_time::milliseconds(1)); - } - lock.unlock(); //unlock before notify - _cond.notify_one(); - - //exit barrier to ensure known condition of entry count - _exit_counter.inc(); - _exit_counter.cas(0, _size); - while (_exit_counter.read() != 0) this->check_interrupt(); - } - - //! Wait on the barrier condition - UHD_INLINE void wait_others(void) - { - while (_entry_counter.read() != (_size-1)) this->check_interrupt(); - } - - private: - size_t _size; - atomic_uint32_t _entry_counter; - atomic_uint32_t _exit_counter; - atomic_uint32_t _done; - boost::mutex _mutex; - boost::condition_variable _cond; - - UHD_INLINE void check_interrupt(void) - { - if (_done.read() != 0) throw boost::thread_interrupted(); - boost::this_thread::interruption_point(); - boost::this_thread::yield(); - } - }; - - /*! * Spin-wait on a condition with a timeout. * \param cond an atomic variable to compare * \param value compare to atomic for true/false diff --git a/host/include/uhd/version.hpp.in b/host/include/uhd/version.hpp.in index 10f6a97ba..f63d973e9 100644 --- a/host/include/uhd/version.hpp.in +++ b/host/include/uhd/version.hpp.in @@ -27,7 +27,7 @@ * The format is oldest API compatible release - ABI compat number. * The compatibility number allows pre-release ABI to be versioned. */ -#define UHD_VERSION_ABI_STRING "@TRIMMED_VERSION_MAJOR@.@TRIMMED_VERSION_API@.@TRIMMED_VERSION_ABI@" +#define UHD_VERSION_ABI_STRING "@UHD_VERSION_MAJOR@.@UHD_VERSION_API@.@UHD_VERSION_ABI@" /*! * A macro to check UHD version at compile-time. diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 0cd89953c..a4be9fd81 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -140,10 +140,10 @@ ENDIF(ENABLE_C_API) # Add DLL resource file to Windows build ######################################################################## IF(MSVC) - MATH(EXPR TRIMMED_VERSION_MAJOR_API "${TRIMMED_VERSION_MAJOR} * 1000 + ${TRIMMED_VERSION_API}") - SET(RC_TRIMMED_VERSION_PATCH ${TRIMMED_VERSION_PATCH}) + MATH(EXPR RC_VERSION_MAJOR_API "${UHD_VERSION_MAJOR} * 1000 + ${UHD_VERSION_API}") + SET(RC_VERSION_PATCH ${UHD_VERSION_PATCH}) IF(UHD_VERSION_DEVEL) - SET(RC_TRIMMED_VERSION_PATCH "999") + SET(RC_VERSION_PATCH "999") ENDIF(UHD_VERSION_DEVEL) # Allow a custom .rc template file to be used diff --git a/host/lib/rfnoc/block_ctrl_base.cpp b/host/lib/rfnoc/block_ctrl_base.cpp index c273fa76b..20299a3c3 100644 --- a/host/lib/rfnoc/block_ctrl_base.cpp +++ b/host/lib/rfnoc/block_ctrl_base.cpp @@ -48,7 +48,6 @@ inline uint32_t _sr_to_addr64(uint32_t reg) { return reg * 8; }; // for peek64 block_ctrl_base::block_ctrl_base( const make_args_t &make_args ) : _tree(make_args.tree), - _transport_is_big_endian(make_args.is_big_endian), _ctrl_ifaces(make_args.ctrl_ifaces), _base_address(make_args.base_address & 0xFFF0) { diff --git a/host/lib/rfnoc/ctrl_iface.cpp b/host/lib/rfnoc/ctrl_iface.cpp index b2ac1778e..8e4474af7 100644 --- a/host/lib/rfnoc/ctrl_iface.cpp +++ b/host/lib/rfnoc/ctrl_iface.cpp @@ -16,7 +16,6 @@ // #include "ctrl_iface.hpp" -#include "async_packet_handler.hpp" #include <uhd/exception.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/byteswap.hpp> @@ -37,7 +36,6 @@ using namespace uhd::transport; static const double ACK_TIMEOUT = 2.0; //supposed to be worst case practical timeout static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command -static const size_t SR_READBACK = 32; ctrl_iface::~ctrl_iface(void){ /* NOP */ @@ -60,13 +58,12 @@ public: _name(name), _seq_out(0), _timeout(ACK_TIMEOUT), - _resp_queue(128/*max response msgs*/), - _resp_queue_size(_resp_xport ? _resp_xport->get_num_recv_frames() : 3), + _resp_queue_size(_resp_xport->get_num_recv_frames()), _rb_address(uhd::rfnoc::SR_READBACK) { - if (resp_xport) { - while (resp_xport->get_recv_buff(0.0)) {} //flush - } + UHD_ASSERT_THROW(_ctrl_xport); + UHD_ASSERT_THROW(_resp_xport); + while (resp_xport->get_recv_buff(0.0)) {} //flush this->set_time(uhd::time_spec_t(0.0)); this->set_tick_rate(1.0); //something possible but bogus } @@ -76,7 +73,6 @@ public: _timeout = ACK_TIMEOUT; //reset timeout to something small UHD_SAFE_CALL( this->peek32(0);//dummy peek with the purpose of ack'ing all packets - _async_task.reset();//now its ok to release the task ) } @@ -196,50 +192,16 @@ private: uint32_t const *pkt = NULL; managed_recv_buffer::sptr buff; - //get buffer from response endpoint - or die in timeout - if (_resp_xport) - { - buff = _resp_xport->get_recv_buff(_timeout); - try - { - UHD_ASSERT_THROW(bool(buff)); - UHD_ASSERT_THROW(buff->size() > 0); - } - catch(const std::exception &ex) - { - throw uhd::io_error(str(boost::format("Block ctrl (%s) no response packet - %s") % _name % ex.what())); - } - pkt = buff->cast<const uint32_t *>(); - packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); + buff = _resp_xport->get_recv_buff(_timeout); + try { + UHD_ASSERT_THROW(bool(buff)); + UHD_ASSERT_THROW(buff->size() > 0); } - - //get buffer from response endpoint - or die in timeout - else - { - /* - * Couldn't get message with haste. - * Now check both possible queues for messages. - * Messages should come in on _resp_queue, - * but could end up in dump_queue. - * If we don't get a message --> Die in timeout. - */ - double accum_timeout = 0.0; - const double short_timeout = 0.005; // == 5ms - while(not ((_resp_queue.pop_with_haste(resp_buff)) - || (check_dump_queue(resp_buff)) - || (_resp_queue.pop_with_timed_wait(resp_buff, short_timeout)) - )){ - /* - * If a message couldn't be received within a given timeout - * --> throw AssertionError! - */ - accum_timeout += short_timeout; - UHD_ASSERT_THROW(accum_timeout < _timeout); - } - - pkt = resp_buff.data; - packet_info.num_packet_words32 = sizeof(resp_buff)/sizeof(uint32_t); + catch(const std::exception &ex) { + throw uhd::io_error(str(boost::format("Block ctrl (%s) no response packet - %s") % _name % ex.what())); } + pkt = buff->cast<const uint32_t *>(); + packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); //parse the buffer try @@ -306,48 +268,11 @@ private: return 0; } - /* - * If ctrl_core waits for a message that didn't arrive it can search for it in the dump queue. - * This actually happens during shutdown. - * handle_async_task can't access queue anymore thus it returns the corresponding message. - * msg_task class implements a dump_queue to store such messages. - * With check_dump_queue we can check if a message we are waiting for got stranded there. - * If a message got stuck we get it here and push it onto our own message_queue. - */ - bool check_dump_queue(resp_buff_type& b) { - const size_t min_buff_size = 8; // Same value as in b200_io_impl->handle_async_task - uint32_t recv_sid = (((_sid)<<16)|((_sid)>>16)); - uhd::msg_task::msg_payload_t msg; - do{ - msg = _async_task->get_msg_from_dump_queue(recv_sid); - } - while(msg.size() < min_buff_size && msg.size() != 0); - - if(msg.size() >= min_buff_size) { - memcpy(b.data, &msg.front(), std::min(msg.size(), sizeof(b.data))); - return true; - } - return false; - } - - void push_response(const uint32_t *buff) - { - resp_buff_type resp_buff; - std::memcpy(resp_buff.data, buff, sizeof(resp_buff)); - _resp_queue.push_with_haste(resp_buff); - } - - void hold_task(uhd::msg_task::sptr task) - { - _async_task = task; - } - const vrt::if_packet_info_t::link_type_t _link_type; const vrt::if_packet_info_t::packet_type_t _packet_type; const bool _bige; const uhd::transport::zero_copy_if::sptr _ctrl_xport; const uhd::transport::zero_copy_if::sptr _resp_xport; - uhd::msg_task::sptr _async_task; const uint32_t _sid; const std::string _name; boost::mutex _mutex; @@ -357,7 +282,6 @@ private: double _tick_rate; double _timeout; std::queue<size_t> _outstanding_seqs; - bounded_buffer<resp_buff_type> _resp_queue; const size_t _resp_queue_size; const size_t _rb_address; diff --git a/host/lib/rfnoc/ctrl_iface.hpp b/host/lib/rfnoc/ctrl_iface.hpp index 3690874f9..5e88c3dd6 100644 --- a/host/lib/rfnoc/ctrl_iface.hpp +++ b/host/lib/rfnoc/ctrl_iface.hpp @@ -47,18 +47,6 @@ public: const std::string &name = "0" ); - //! Hold a ref to a task thats feeding push response - virtual void hold_task(uhd::msg_task::sptr task) = 0; - - //! Push a response externall (resp_xport is NULL) - virtual void push_response(const uint32_t *buff) = 0; - - //! Set the command time that will activate - virtual void set_time(const uhd::time_spec_t &time) = 0; - - //! Get the command time that will activate - virtual uhd::time_spec_t get_time(void) = 0; - //! Set the tick rate (converting time into ticks) virtual void set_tick_rate(const double rate) = 0; }; diff --git a/host/lib/rfnoc/xports.hpp b/host/lib/rfnoc/xports.hpp index 7872f2e1b..1ce05c6c8 100644 --- a/host/lib/rfnoc/xports.hpp +++ b/host/lib/rfnoc/xports.hpp @@ -16,6 +16,7 @@ // #include <uhd/types/sid.hpp> +#include <uhd/types/endianness.hpp> #include <uhd/transport/zero_copy.hpp> namespace uhd { @@ -30,6 +31,7 @@ namespace uhd { size_t send_buff_size; uhd::sid_t send_sid; uhd::sid_t recv_sid; + uhd::endianness_t endianness; }; }; diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp index b697bd614..40f84a2aa 100644 --- a/host/lib/types/sid.cpp +++ b/host/lib/types/sid.cpp @@ -1,5 +1,5 @@ // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-2016 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 @@ -15,12 +15,12 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/types/sid.hpp> +#include <uhd/exception.hpp> +#include <uhd/utils/cast.hpp> #include <boost/format.hpp> #include <boost/regex.hpp> #include <boost/lexical_cast.hpp> -#include <uhd/exception.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/utils/cast.hpp> using namespace uhd; @@ -141,7 +141,7 @@ void sid_t::set_dst_blockport(uint32_t new_blockport) set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0)); } -sid_t sid_t::reversed() +sid_t sid_t::reversed() const { return sid_t((get_dst() << 16) | get_src()); } diff --git a/host/lib/uhd.rc.in b/host/lib/uhd.rc.in index 24177a00a..dee6bb8a3 100644 --- a/host/lib/uhd.rc.in +++ b/host/lib/uhd.rc.in @@ -1,8 +1,8 @@ #include <windows.h> VS_VERSION_INFO VERSIONINFO - FILEVERSION @TRIMMED_VERSION_MAJOR_API@,@TRIMMED_VERSION_ABI@,@RC_TRIMMED_VERSION_PATCH@,@UHD_GIT_COUNT@ - PRODUCTVERSION @TRIMMED_VERSION_MAJOR_API@,@TRIMMED_VERSION_ABI@,@RC_TRIMMED_VERSION_PATCH@,@UHD_GIT_COUNT@ + FILEVERSION @RC_VERSION_MAJOR_API@,@UHD_VERSION_ABI@,@RC_VERSION_PATCH@,@UHD_GIT_COUNT@ + PRODUCTVERSION @RC_VERSION_MAJOR_API@,@UHD_VERSION_ABI@,@RC_VERSION_PATCH@,@UHD_GIT_COUNT@ FILEFLAGSMASK 0x3fL #ifndef NDEBUG FILEFLAGS 0x0L diff --git a/host/lib/usrp/device3/device3_impl.cpp b/host/lib/usrp/device3/device3_impl.cpp index 50598a519..28b7bc34b 100644 --- a/host/lib/usrp/device3/device3_impl.cpp +++ b/host/lib/usrp/device3/device3_impl.cpp @@ -105,8 +105,7 @@ void device3_impl::enumerate_rfnoc_blocks( size_t n_blocks, size_t base_port, const uhd::sid_t &base_sid, - uhd::device_addr_t transport_args, - uhd::endianness_t endianness + uhd::device_addr_t transport_args ) { // entries that are already connected to this block uhd::sid_t ctrl_sid = base_sid; @@ -131,7 +130,7 @@ void device3_impl::enumerate_rfnoc_blocks( ); UHD_DEVICE3_LOG() << str(boost::format("Setting up NoC-Shell Control for port #0 (SID: %s)...") % xport.send_sid.to_pp_string_hex()); uhd::rfnoc::ctrl_iface::sptr ctrl = uhd::rfnoc::ctrl_iface::make( - endianness == ENDIANNESS_BIG, + xport.endianness == uhd::ENDIANNESS_BIG, xport.send, xport.recv, xport.send_sid, @@ -160,7 +159,7 @@ void device3_impl::enumerate_rfnoc_blocks( ); UHD_DEVICE3_LOG() << str(boost::format("Setting up NoC-Shell Control for port #%d (SID: %s)...") % port_number % xport1.send_sid.to_pp_string_hex()); uhd::rfnoc::ctrl_iface::sptr ctrl1 = uhd::rfnoc::ctrl_iface::make( - endianness == ENDIANNESS_BIG, + xport1.endianness == uhd::ENDIANNESS_BIG, xport1.send, xport1.recv, xport1.send_sid, @@ -173,7 +172,6 @@ void device3_impl::enumerate_rfnoc_blocks( make_args.base_address = xport.send_sid.get_dst(); make_args.device_index = device_index; make_args.tree = subtree; - make_args.is_big_endian = (endianness == ENDIANNESS_BIG); _rfnoc_block_ctrl.push_back(uhd::rfnoc::block_ctrl_base::make(make_args, noc_id)); } } diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp index 117e4af1c..c496b5105 100644 --- a/host/lib/usrp/device3/device3_impl.hpp +++ b/host/lib/usrp/device3/device3_impl.hpp @@ -134,7 +134,6 @@ protected: virtual uhd::device_addr_t get_tx_hints(size_t) { return uhd::device_addr_t(); }; virtual uhd::device_addr_t get_rx_hints(size_t) { return uhd::device_addr_t(); }; - virtual uhd::endianness_t get_transport_endianness(size_t mb_index) = 0; //! Is called after a streamer is generated virtual void post_streamer_hooks(uhd::direction_t) {}; @@ -167,8 +166,7 @@ protected: size_t n_blocks, size_t base_port, const uhd::sid_t &base_sid, - uhd::device_addr_t transport_args, - uhd::endianness_t endianness + uhd::device_addr_t transport_args ); /*********************************************************************** diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp index 4ec14c43b..a490ae5b4 100644 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ b/host/lib/usrp/device3/device3_io_impl.cpp @@ -571,7 +571,7 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) //init some streamer stuff std::string conv_endianness; - if (get_transport_endianness(mb_index) == ENDIANNESS_BIG) { + if (xport.endianness == ENDIANNESS_BIG) { my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be); conv_endianness = "be"; } else { @@ -624,7 +624,7 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) &handle_rx_flowctrl, xport.send_sid, xport.send, - get_transport_endianness(mb_index), + xport.endianness, fc_cache, _1 ), @@ -761,7 +761,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) //init some streamer stuff std::string conv_endianness; - if (get_transport_endianness(mb_index) == ENDIANNESS_BIG) { + if (xport.endianness == ENDIANNESS_BIG) { my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be); conv_endianness = "be"; } else { @@ -809,7 +809,7 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) &handle_tx_async_msgs, fc_cache, xport.recv, - get_transport_endianness(mb_index), + xport.endianness, tick_rate_retriever ) ); diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 959245135..548f7bd9c 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -942,8 +942,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) n_rfnoc_blocks, X300_XB_DST_PCI + 1, /* base port */ uhd::sid_t(X300_SRC_ADDR0, 0, X300_DST_ADDR + mb_i, 0), - dev_addr, - mb.if_pkt_is_big_endian ? ENDIANNESS_BIG : ENDIANNESS_LITTLE + dev_addr ); //////////////// RFNOC ///////////////// @@ -1063,6 +1062,7 @@ uhd::both_xports_t x300_impl::make_transport( zero_copy_xport_params default_buff_args; both_xports_t xports; + xports.endianness = mb.if_pkt_is_big_endian ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; if (mb.xport_path == "nirio") { xports.send_sid = this->allocate_sid(mb, address, X300_SRC_ADDR0, X300_XB_DST_PCI); xports.recv_sid = xports.send_sid.reversed(); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index ff18b1a22..3ae37b54a 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -277,9 +277,6 @@ private: /// More IO stuff uhd::device_addr_t get_tx_hints(size_t mb_index); uhd::device_addr_t get_rx_hints(size_t mb_index); - uhd::endianness_t get_transport_endianness(size_t mb_index) { - return _mb[mb_index].if_pkt_is_big_endian ? uhd::ENDIANNESS_BIG : uhd::ENDIANNESS_LITTLE; - }; void post_streamer_hooks(uhd::direction_t dir); }; diff --git a/host/tests/device3_test.cpp b/host/tests/device3_test.cpp index 657436717..a81f4ca0a 100644 --- a/host/tests/device3_test.cpp +++ b/host/tests/device3_test.cpp @@ -87,7 +87,6 @@ class pseudo_device3_impl : public uhd::device3 make_args.base_address = TEST_SID0.get_dst(); make_args.device_index = 0; make_args.tree = _tree; - make_args.is_big_endian = false; std::cout << "[PSEUDO] Generating block controls 1/2:" << std::endl; _rfnoc_block_ctrl.push_back( block_ctrl_base::make(make_args) ); diff --git a/host/tests/sid_t_test.cpp b/host/tests/sid_t_test.cpp index 2043398a1..e07e1c9bc 100644 --- a/host/tests/sid_t_test.cpp +++ b/host/tests/sid_t_test.cpp @@ -118,8 +118,9 @@ BOOST_AUTO_TEST_CASE(test_sid_t_set) { BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c); BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0xbc); - sid_t flipped_sid = sid.reversed(); + const sid_t flipped_sid = sid.reversed(); BOOST_CHECK_EQUAL(flipped_sid.get(), (uint32_t)0x0cbc0a0b); + BOOST_CHECK_EQUAL(flipped_sid.reversed(), sid); // In-place sid.reverse(); diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index eb5a29df9..33cb5a972 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -156,9 +156,7 @@ ENDIF(NOT HAVE_PYTHON_MODULE_REQUESTS) IF(ENABLE_USRP2) SET(burners usrp2_card_burner.py - usrp2_card_burner_gui.py usrp_n2xx_net_burner.py - usrp_n2xx_net_burner_gui.py ) IF(WIN32 AND UHD_RELEASE_MODE) #include dd.exe diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index 4ffaeb0d7..57d6f3cc8 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -15,95 +15,12 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <algorithm> -#include <csignal> -#include <iostream> -#include <fstream> -#include <stdexcept> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> #include <boost/program_options.hpp> -#include <boost/assign.hpp> -#include <stdint.h> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread.hpp> - -#include <uhd/device.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/types/time_spec.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> - -#include "../lib/usrp_clock/octoclock/common.h" -#include "../lib/utils/ihex.hpp" - -#define MAX_FIRMWARE_SIZE 1024*120 -#define BLOCK_SIZE 256 -#define UDP_TIMEOUT 5 +#include <iostream> -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace uhd; -using namespace uhd::transport; - -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "OctoClock device will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your OctoClock device will be bricked." << std::endl - << "Refer to http://files.ettus.com/manual/page_octoclock.html#bootloader" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -uint8_t firmware_image[MAX_FIRMWARE_SIZE]; -size_t firmware_size = 0; -uint8_t octoclock_data[udp_simple::mtu]; -octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t *>(octoclock_data); -std::string firmware_path, actual_firmware_path; -size_t num_blocks = 0; -bool hex = true; - -static uint16_t calculate_crc(uint8_t* buffer, uint16_t len){ - uint16_t crc = 0xFFFF; - - for(size_t i = 0; i < len; i++){ - crc ^= buffer[i]; - for(uint8_t j = 0; j < 8; ++j){ - if(crc & 1) crc = (crc >> 1) ^ 0xA001; - else crc = (crc >> 1); - } - } - - return crc; -} - -/* - * Functions - */ -void list_octoclocks(){ - device_addrs_t found_octoclocks = device::find(uhd::device_addr_t(), device::CLOCK); - - std::cout << "Available OctoClock devices:" << std::endl; - BOOST_FOREACH(const device_addr_t &oc, found_octoclocks){ - std::cout << " * " << oc["addr"] << std::endl; - } -} - void print_image_loader_warning(const std::string &fw_path, const po::variables_map &vm){ // Newline + indent #ifdef UHD_PLATFORM_WIN32 @@ -115,10 +32,8 @@ void print_image_loader_warning(const std::string &fw_path, const po::variables_ std::string uhd_image_loader = str(boost::format("uhd_image_loader --args=\"type=octoclock,addr=%s\"" "%s --fw-path=%s") % vm["addr"].as<std::string>() % nl % fw_path); - std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -126,301 +41,21 @@ void print_image_loader_warning(const std::string &fw_path, const po::variables_ << std::endl; } -/* - * Manually find bootloader. This sends multiple packets in order to increase chances of getting - * bootloader before it switches to the application. - */ -device_addrs_t bootloader_find(const std::string &ip_addr){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); - - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<uint32_t>(std::rand()); - pkt_out.code = OCTOCLOCK_QUERY_CMD; - pkt_out.len = 0; - size_t len = 0; - - device_addrs_t addrs; - - boost::system_time comm_timeout = boost::get_system_time() + boost::posix_time::milliseconds(3000); - - while(boost::get_system_time() < comm_timeout){ - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, OCTOCLOCK_QUERY_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len) and - pkt_in->proto_ver == OCTOCLOCK_BOOTLOADER_PROTO_VER){ - addrs.push_back(device_addr_t()); - addrs[0]["type"] = "octoclock-bootloader"; - addrs[0]["addr"] = udp_transport->get_recv_addr(); - break; - } - } - - return addrs; -} - -void read_firmware(){ - std::ifstream firmware_file(actual_firmware_path.c_str(), std::ios::binary); - firmware_size = size_t(fs::file_size(actual_firmware_path)); - if(firmware_size > MAX_FIRMWARE_SIZE){ - firmware_file.close(); - throw uhd::runtime_error(str(boost::format("Firmware file too large: %d > %d") - % firmware_size % (MAX_FIRMWARE_SIZE))); - } - firmware_file.read((char*)firmware_image, firmware_size); - firmware_file.close(); - - num_blocks = (firmware_size % BLOCK_SIZE) ? ((firmware_size / BLOCK_SIZE) + 1) - : (firmware_size / BLOCK_SIZE); -} - -void burn_firmware(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<uint32_t>(std::rand()); - pkt_out.len = (uint16_t)firmware_size; - pkt_out.crc = calculate_crc(firmware_image, firmware_size); - size_t len = 0, current_pos = 0; - - //Tell OctoClock not to jump to application, wait for us instead - std::cout << "Telling OctoClock to prepare for firmware download..." << std::flush; - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, PREPARE_FW_BURN_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl; - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download."); - } - - std::cout << std::endl << "Burning firmware." << std::endl; - pkt_out.code = FILE_TRANSFER_CMD; - - //Actual burning below - size_t num_tries = 0; - for(size_t i = 0; i < num_blocks; i++){ - num_tries = 0; - pkt_out.sequence++; - pkt_out.addr = i*BLOCK_SIZE; - std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) - << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; - - memset(pkt_out.data, 0, BLOCK_SIZE); - memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], BLOCK_SIZE); - - bool success = false; - while(num_tries <= 5){ - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){ - success = true; - break; - } - else{ - num_tries++; - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } - } - if(not success){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to burn firmware to OctoClock!"); - } - - current_pos += BLOCK_SIZE; - } - - std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; -} - -void verify_firmware(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM; - pkt_out.sequence = uhd::htonx<uint32_t>(std::rand()); - size_t len = 0, current_pos = 0; - - for(size_t i = 0; i < num_blocks; i++){ - pkt_out.sequence++; - pkt_out.addr = i*BLOCK_SIZE; - std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) - << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, READ_FW_CMD, pkt_out, len, octoclock_data); - if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){ - if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE], - std::min(int(firmware_size-current_pos), BLOCK_SIZE))){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to verify OctoClock firmware!"); - } - } - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to verify OctoClock firmware!"); - } - } - - std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; -} - -bool reset_octoclock(const std::string &ip_addr){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); - - octoclock_packet_t pkt_out; - pkt_out.sequence = uhd::htonx<uint32_t>(std::rand()); - size_t len; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, RESET_CMD, pkt_out, len, octoclock_data); - if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to place device in state to receive firmware."); - } - - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - return (bootloader_find(ip_addr).size() == 1); -} - -void finalize(udp_simple::sptr udp_transport){ - octoclock_packet_t pkt_out; - pkt_out.len = 0; - pkt_out.sequence = uhd::htonx<uint32_t>(std::rand()); - size_t len = 0; - - UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_FW_COMPAT_NUM, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data); - if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - std::cout << "no ACK. Bootloader may not have loaded application." << std::endl; - } -} - -void octoclock_convert_ihex(const std::string &hex_path, const std::string &bin_path){ - ihex_reader hex_reader(hex_path); - hex_reader.to_bin_file(bin_path); -} - -int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ - - std::string ip_addr; +int main(int argc, const char *argv[]) +{ + std::string ip_addr, firmware_path; po::options_description desc("Allowed options"); desc.add_options() ("help", "Display this help message.") - ("addr", po::value<std::string>(&ip_addr), "Specify an IP address.") - ("fw-path", po::value<std::string>(&firmware_path), "Specify a custom firmware path.") + ("addr", po::value<std::string>(&ip_addr)->default_value("addr=1.2.3.4"), "Specify an IP address.") + ("fw-path", po::value<std::string>(&firmware_path)->default_value("path/to/firmware"), "Specify a custom firmware path.") ("list", "List all available OctoClock devices.") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help")){ - std::cout << "OctoClock Firmware Burner" << std::endl << std::endl; - - std::cout << "Burns a firmware image file onto an OctoClock device. Specify" << std::endl - << "the address of the OctoClock with the --addr option. To burn" << std::endl - << "a custom firmware image, use the --fw-path option. Otherwise, the" << std::endl - << "utility will use the default image. To list all available" << std::endl - << "OctoClock devices without burning firmware, use the --list" << std::endl - << "option." << std::endl << std::endl; - - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List all available devices - if(vm.count("list")){ - list_octoclocks(); - return EXIT_SUCCESS; - } - - if(not (vm.count("addr"))){ - throw uhd::runtime_error("You must specify an address with the --addr option!"); - } - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_FW_PORT)); - - //If custom path given, make sure it exists - if(vm.count("fw-path")){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(firmware_path.find("~/") == 0) firmware_path.replace(0,1,getenv("HOME")); - #endif - - if(not fs::exists(firmware_path)){ - throw uhd::runtime_error(str(boost::format("This filepath does not exist: %s") % firmware_path)); - } - } - else firmware_path = find_image_path("octoclock_r4_fw.hex"); - - //If Intel hex file detected, convert to binary - std::string ext = fs::extension(firmware_path); - if(ext == ".hex"){ - std::cout << "Found firmware at path: " << firmware_path << std::endl; - - //Write firmware .bin file to temporary directory - fs::path temp_bin = fs::path(fs::path(get_tmp_path()) / str(boost::format("octoclock_fw_%d.bin") - % time_spec_t::get_system_time().get_full_secs())); - octoclock_convert_ihex(firmware_path, temp_bin.string()); - - actual_firmware_path = temp_bin.string(); - } - else if(ext == ".bin"){ - hex = false; - actual_firmware_path = firmware_path; - std::cout << "Found firmware at path: " << firmware_path << std::endl; - } - else throw uhd::runtime_error("The firmware file has in improper extension (must be .hex or .bin)."); - - std::cout << std::endl << boost::format("Searching for OctoClock with IP address %s...") % ip_addr << std::flush; - device_addrs_t octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); - if(octoclocks.size() == 1){ - if(octoclocks[0]["type"] == "octoclock"){ - std::cout << "found. Resetting..." << std::flush; - if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl; - else{ - std::cout << "failed." << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader."); - } - } - else std::cout << "found." << std::endl; - } - else{ - std::cout << "failed." << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Could not find OctoClock with given IP address!"); - } - - read_firmware(); - print_image_loader_warning(firmware_path, vm); - std::signal(SIGINT, &sig_int_handler); - - burn_firmware(udp_transport); - std::cout << "Verifying firmware." << std::endl; - verify_firmware(udp_transport); - std::cout << std::endl << "Telling OctoClock bootloader to load application..." << std::flush; - finalize(udp_transport); - std::cout << "done." << std::endl; - - std::cout << "Waiting for OctoClock to reinitialize..." << std::flush; - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); - if(octoclocks.size() == 1){ - if(octoclocks[0]["type"] == "octoclock-bootloader"){ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Firmware did not load properly."); - } - else{ - std::cout << "found." << std::endl << std::endl - << "Successfully burned firmware." << std::endl << std::endl; - } - } - else{ - std::cout << std::endl; - if(hex) fs::remove(actual_firmware_path); - throw uhd::runtime_error("Failed to reinitialize OctoClock."); - } - if(hex) fs::remove(actual_firmware_path); - - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py index 5605b0028..372078f91 100755 --- a/host/utils/usrp_n2xx_net_burner.py +++ b/host/utils/usrp_n2xx_net_burner.py @@ -16,8 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -# TODO: make it autodetect UHD devices - import optparse import math import os @@ -29,72 +27,7 @@ import time import platform import subprocess -######################################################################## -# constants -######################################################################## -UDP_FW_UPDATE_PORT = 49154 -UDP_MAX_XFER_BYTES = 1024 -UDP_TIMEOUT = 3 -UDP_POLL_INTERVAL = 0.10 #in seconds - -USRP2_FW_PROTO_VERSION = 7 #should be unused after r6 - -#from bootloader_utils.h - -FPGA_IMAGE_SIZE_BYTES = 1572864 -FW_IMAGE_SIZE_BYTES = 31744 -SAFE_FPGA_IMAGE_LOCATION_ADDR = 0x00000000 -SAFE_FW_IMAGE_LOCATION_ADDR = 0x003F0000 -PROD_FPGA_IMAGE_LOCATION_ADDR = 0x00180000 -PROD_FW_IMAGE_LOCATION_ADDR = 0x00300000 - -FLASH_DATA_PACKET_SIZE = 256 - -#see fw_common.h -FLASH_ARGS_FMT = '!LLLLL256s' -FLASH_INFO_FMT = '!LLLLL256x' -FLASH_IP_FMT = '!LLLL260x' -FLASH_HW_REV_FMT = '!LLLL260x' - -n2xx_revs = { - 0x0a00: ["n200_r3", "n200_r2"], - 0x0a10: ["n200_r4"], - 0x0a01: ["n210_r3", "n210_r2"], - 0x0a11: ["n210_r4"] - } - -class update_id_t: - USRP2_FW_UPDATE_ID_WAT = ord(' ') - USRP2_FW_UPDATE_ID_OHAI_LOL = ord('a') - USRP2_FW_UPDATE_ID_OHAI_OMG = ord('A') - USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = ord('f') - USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = ord('F') - USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = ord('e') - USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = ord('E') - USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = ord('d') - USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = ord('D') - USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = ord('B') - USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = ord('w') - USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = ord('W') - USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = ord('r') - USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = ord('R') - USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = ord('s') - USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = ord('S') - USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = ord('v') - USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = ord('V') - USRP2_FW_UPDATE_ID_KTHXBAI = ord('~') - -_seq = -1 -def seq(): - global _seq - _seq = _seq+1 - return _seq - -######################################################################## -# print equivalent uhd_image_loader command -######################################################################## def print_image_loader_warning(fw, fpga, reset, safe, addr): - # Newline + indent if platform.system() == "Windows": nl = " ^\n " @@ -121,8 +54,7 @@ def print_image_loader_warning(fw, fpga, reset, safe, addr): print("") print("************************************************************************************************") - print("WARNING: This utility will be removed in an upcoming version of UHD. In the future, use") - print(" this command:") + print("ERROR: This utility has been removed in this version of UHD. Use this command:") print("") print(uhd_image_loader) print("") @@ -130,383 +62,16 @@ def print_image_loader_warning(fw, fpga, reset, safe, addr): print("") ######################################################################## -# helper functions -######################################################################## -def unpack_flash_args_fmt(s): - return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data) - -def unpack_flash_info_fmt(s): - return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes) - -def unpack_flash_ip_fmt(s): - return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr) - -def unpack_flash_hw_rev_fmt(s): - return struct.unpack(FLASH_HW_REV_FMT, s) #proto_ver, pktid, seq, hw_rev - -def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data=bytes()): - return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data) - -def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes): - return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes) - -def pack_flash_hw_rev_fmt(proto_ver, pktid, seq, hw_rev): - return struct.pack(FLASH_HW_REV_FMT, proto_ver, pktid, seq, hw_rev) - -def is_valid_fpga_image(fpga_image): - for i in range(0,63): - if fpga_image[i:i+1] == bytes(b'\xFF'): continue - if fpga_image[i:i+2] == bytes(b'\xAA\x99'): return True - return False - -def is_valid_fw_image(fw_image): - return fw_image[:4] == bytes(b'\x0B\x0B\x0B\x0B') - - -######################################################################## -# interface discovery and device enumeration -######################################################################## -def command(*args): - p = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - ret = p.wait() - verbose = p.stdout.read().decode('utf-8') - if ret != 0: raise Exception(verbose) - return verbose - -def get_interfaces(): - if(platform.system() is "Windows"): return win_get_interfaces() - else: return unix_get_interfaces() - -def unix_get_interfaces(): - ifconfig = command("/sbin/ifconfig") - ip_addr_re = "cast\D*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" - bcasts = re.findall(ip_addr_re, ifconfig) - return bcasts - -def win_get_interfaces(): - from ctypes import Structure, windll, sizeof - from ctypes import POINTER, byref - from ctypes import c_ulong, c_uint, c_ubyte, c_char - MAX_ADAPTER_DESCRIPTION_LENGTH = 128 - MAX_ADAPTER_NAME_LENGTH = 256 - MAX_ADAPTER_ADDRESS_LENGTH = 8 - class IP_ADDR_STRING(Structure): - pass - LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING) - IP_ADDR_STRING._fields_ = [ - ("next", LP_IP_ADDR_STRING), - ("ipAddress", c_char * 16), - ("ipMask", c_char * 16), - ("context", c_ulong)] - class IP_ADAPTER_INFO (Structure): - pass - LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO) - IP_ADAPTER_INFO._fields_ = [ - ("next", LP_IP_ADAPTER_INFO), - ("comboIndex", c_ulong), - ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)), - ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)), - ("addressLength", c_uint), - ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH), - ("index", c_ulong), - ("type", c_uint), - ("dhcpEnabled", c_uint), - ("currentIpAddress", LP_IP_ADDR_STRING), - ("ipAddressList", IP_ADDR_STRING), - ("gatewayList", IP_ADDR_STRING), - ("dhcpServer", IP_ADDR_STRING), - ("haveWins", c_uint), - ("primaryWinsServer", IP_ADDR_STRING), - ("secondaryWinsServer", IP_ADDR_STRING), - ("leaseObtained", c_ulong), - ("leaseExpires", c_ulong)] - GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo - GetAdaptersInfo.restype = c_ulong - GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)] - adapterList = (IP_ADAPTER_INFO * 10)() - buflen = c_ulong(sizeof(adapterList)) - rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen)) - if rc == 0: - for a in adapterList: - adNode = a.ipAddressList - while True: - #convert ipAddr and ipMask into hex addrs that can be turned into a bcast addr - try: - ipAddr = adNode.ipAddress.decode() - ipMask = adNode.ipMask.decode() - except: ipAddr = None - if ipAddr and ipMask: - hexAddr = struct.unpack("<L", socket.inet_aton(ipAddr))[0] - hexMask = struct.unpack("<L", socket.inet_aton(ipMask))[0] - if(hexAddr and hexMask): #don't broadcast on 255.255.255.255, that's just lame - yield socket.inet_ntoa(struct.pack("<L", (hexAddr & hexMask) | (~hexMask) & 0xFFFFFFFF)) - try: adNode = adNode.next - except: break - if not adNode: break - -def enumerate_devices(): - for bcast_addr in get_interfaces(): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - sock.settimeout(0.1) - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, 0, 0, 0) - sock.sendto(out_pkt, (bcast_addr, UDP_FW_UPDATE_PORT)) - still_goin = True - while(still_goin): - try: - pkt = sock.recv(UDP_MAX_XFER_BYTES) - (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(pkt) - if(pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG): - use_addr = socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr))) - burner = burner_socket(use_addr, True) - yield "%s (%s)" % (socket.inet_ntoa(struct.pack("<L", socket.ntohl(ip_addr))), n2xx_revs[burner.get_hw_rev()][0]) - except socket.timeout: - still_goin = False - -######################################################################## # Burner class, holds a socket and send/recv routines ######################################################################## class burner_socket(object): - def __init__(self, addr, quiet): - self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + def __init__(self, addr): self._addr = addr - self._quiet = quiet - self._sock.settimeout(UDP_TIMEOUT) - self._sock.connect((addr, UDP_FW_UPDATE_PORT)) - self.set_callbacks(lambda *a: None, lambda *a: None) - self.init_update(quiet) #check that the device is there - self.get_hw_rev() - - def set_callbacks(self, progress_cb, status_cb): - self._progress_cb = progress_cb - self._status_cb = status_cb - - def send_and_recv(self, pkt): - self._sock.send(pkt) - return self._sock.recv(UDP_MAX_XFER_BYTES) - - #just here to validate comms - def init_update(self,quiet): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0) - try: in_pkt = self.send_and_recv(out_pkt) - except socket.timeout: raise Exception("No response from device") - (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt) - if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG: - if not quiet: print("USRP-N2XX found.") - else: - raise Exception("Invalid reply received from device.") - - def get_hw_rev(self): - out_pkt = pack_flash_hw_rev_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL, seq(), 0) - in_pkt = self.send_and_recv(out_pkt) - (proto_ver, pktid, rxseq, hw_rev) = unpack_flash_hw_rev_fmt(in_pkt) - if(pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG): hw_rev = 0 - return socket.ntohs(hw_rev) - - memory_size_bytes = 0 - sector_size_bytes = 0 - def get_flash_info(self): - if (self.memory_size_bytes != 0) and (self.sector_size_bytes != 0): - return (self.memory_size_bytes, self.sector_size_bytes) - - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, self.sector_size_bytes, self.memory_size_bytes) = unpack_flash_info_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - return (self.memory_size_bytes, self.sector_size_bytes) def burn_fw(self, fw, fpga, reset, safe, check_rev=True): + " Just a dummy lol " print_image_loader_warning(fw, fpga, reset, safe, self._addr) - (flash_size, sector_size) = self.get_flash_info() - hw_rev = self.get_hw_rev() - - if hw_rev in n2xx_revs: print("Hardware type: %s" % n2xx_revs[hw_rev][0]) - print("Flash size: %i\nSector size: %i\n" % (flash_size, sector_size)) - - if fpga: - #validate fpga image name against hardware rev - if(check_rev and hw_rev != 0 and not any(name in fpga for name in n2xx_revs[hw_rev])): - raise Exception("Error: incorrect FPGA image version. Please use the correct image for device %s" % n2xx_revs[hw_rev][0]) - - if safe: image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR - else: image_location = PROD_FPGA_IMAGE_LOCATION_ADDR - - fpga_file = open(fpga, 'rb') - fpga_image = fpga_file.read() - - if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES: - raise Exception("Error: FPGA image file too large.") - - if not is_valid_fpga_image(fpga_image): - raise Exception("Error: Invalid FPGA image file.") - - if (len(fpga_image) + image_location) > flash_size: - raise Exception("Error: Cannot write past end of device") - - print("Begin FPGA write: this should take about 1 minute...") - start_time = time.time() - self.erase_image(image_location, FPGA_IMAGE_SIZE_BYTES) - self.write_image(fpga_image, image_location) - self.verify_image(fpga_image, image_location) - print("Time elapsed: %f seconds"%(time.time() - start_time)) - print("\n\n") - - if fw: - if safe: image_location = SAFE_FW_IMAGE_LOCATION_ADDR - else: image_location = PROD_FW_IMAGE_LOCATION_ADDR - - fw_file = open(fw, 'rb') - fw_image = fw_file.read() - - if len(fw_image) > FW_IMAGE_SIZE_BYTES: - raise Exception("Error: Firmware image file too large.") - - if not is_valid_fw_image(fw_image): - raise Exception("Error: Invalid firmware image file.") - - if (len(fw_image) + image_location) > flash_size: - raise Exception("Error: Cannot write past end of device") - - print("Begin firmware write: this should take about 1 second...") - start_time = time.time() - self.erase_image(image_location, FW_IMAGE_SIZE_BYTES) - self.write_image(fw_image, image_location) - self.verify_image(fw_image, image_location) - print("Time elapsed: %f seconds"%(time.time() - start_time)) - print("\n\n") - - if reset: self.reset_usrp() - - def write_image(self, image, addr): - print("Writing image") - self._status_cb("Writing") - writedata = image - #we split the image into smaller (256B) bits and send them down the wire - (mem_size, sector_size) = self.get_flash_info() - if (addr + len(writedata)) > mem_size: - raise Exception("Error: Cannot write past end of device") - - while writedata: - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, writedata[:FLASH_DATA_PACKET_SIZE]) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - writedata = writedata[FLASH_DATA_PACKET_SIZE:] - addr += FLASH_DATA_PACKET_SIZE - self._progress_cb(float(len(image)-len(writedata))/len(image)) - - def verify_image(self, image, addr): - print("Verifying data") - self._status_cb("Verifying") - readsize = len(image) - readdata = bytes() - while readsize > 0: - if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize - else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - readdata += data[:thisreadsize] - readsize -= FLASH_DATA_PACKET_SIZE - addr += FLASH_DATA_PACKET_SIZE - self._progress_cb(float(len(readdata))/len(image)) - - print("Read back %i bytes" % len(readdata)) - # print readdata - - # for i in range(256, 512): - # print "out: %i in: %i" % (ord(image[i]), ord(readdata[i])) - - if readdata != image: - raise Exception("Verify failed. Image did not write correctly.") - else: - print("Success.") - - def read_image(self, image, size, addr): - print("Reading image") - readsize = size - readdata = str() - while readsize > 0: - if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize - else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - readdata += data[:thisreadsize] - readsize -= FLASH_DATA_PACKET_SIZE - addr += FLASH_DATA_PACKET_SIZE - - print("Read back %i bytes" % len(readdata)) - - #write to disk - f = open(image, 'w') - f.write(readdata) - f.close() - - def reset_usrp(self): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0) - try: in_pkt = self.send_and_recv(out_pkt) - except socket.timeout: return - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG: - raise Exception("Device failed to reset.") - - def erase_image(self, addr, length): - self._status_cb("Erasing") - #get flash info first - (flash_size, sector_size) = self.get_flash_info() - if (addr + length) > flash_size: - raise Exception("Cannot erase past end of device") - - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid != update_id_t.USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - - print("Erasing %i bytes at %i" % (length, addr)) - start_time = time.time() - - #now wait for it to finish - while(True): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0) - in_pkt = self.send_and_recv(out_pkt) - - (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) - - if pktid == update_id_t.USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG: break - elif pktid != update_id_t.USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG: - raise Exception("Invalid reply %c from device." % (chr(pktid))) - time.sleep(0.01) #decrease network overhead by waiting a bit before polling - self._progress_cb(min(1.0, (time.time() - start_time)/(length/80e3))) - - ######################################################################## # command line options ######################################################################## @@ -529,47 +94,4 @@ def get_options(): ######################################################################## if __name__=='__main__': options = get_options() - - if options.list: - print('Possible network devices:') - print(' ' + '\n '.join(enumerate_devices())) - #enumerate_devices() - exit() - - if not options.addr: raise Exception('no address specified') - - if not options.fpga and not options.fw and not options.reset: raise Exception('Must specify either a firmware image or FPGA image, and/or reset.') - - if options.overwrite_safe and not options.read: - print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.") - print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.") - - python_major_version = int(platform.python_version_tuple()[0]) - if python_major_version > 2: - response = input("""Type "yes" to continue, or anything else to quit: """) - else: - response = raw_input("""Type "yes" to continue, or anything else to quit: """) - if response != "yes": sys.exit(0) - - burner = burner_socket(addr=options.addr,quiet=False) - - if options.read: - if options.fw: - file = options.fw - if os.path.isfile(file): - response = raw_input("File already exists -- overwrite? (y/n) ") - if response != "y": sys.exit(0) - size = FW_IMAGE_SIZE_BYTES - addr = SAFE_FW_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FW_IMAGE_LOCATION_ADDR - burner.read_image(file, size, addr) - - if options.fpga: - file = options.fpga - if os.path.isfile(file): - response = input("File already exists -- overwrite? (y/n) ") - if response != "y": sys.exit(0) - size = FPGA_IMAGE_SIZE_BYTES - addr = SAFE_FPGA_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FPGA_IMAGE_LOCATION_ADDR - burner.read_image(file, size, addr) - - else: burner.burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe, check_rev=not options.dont_check_rev) + burner_socket(options.addr).burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe, check_rev=not options.dont_check_rev) diff --git a/host/utils/usrp_n2xx_net_burner_gui.py b/host/utils/usrp_n2xx_net_burner_gui.py deleted file mode 100755 index bad065f08..000000000 --- a/host/utils/usrp_n2xx_net_burner_gui.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2011 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 <http://www.gnu.org/licenses/>. -# - -import usrp_n2xx_net_burner #import implementation -try: - import tkinter, tkinter.filedialog, tkinter.font, tkinter.messagebox -except ImportError: - import tkFileDialog, tkFont, tkMessageBox - import Tkinter as tkinter - tkinter.filedialog = tkFileDialog - tkinter.font = tkFont - tkinter.messagebox = tkMessageBox -import os - -class BinFileEntry(tkinter.Frame): - """ - Simple file entry widget for getting the file path of bin files. - Combines a label, entry, and button with file dialog callback. - """ - - def __init__(self, root, what, def_path=''): - self._what = what - tkinter.Frame.__init__(self, root) - tkinter.Label(self, text=what+":").pack(side=tkinter.LEFT) - self._entry = tkinter.Entry(self, width=50) - self._entry.insert(tkinter.END, def_path) - self._entry.pack(side=tkinter.LEFT) - tkinter.Button(self, text="...", command=self._button_cb).pack(side=tkinter.LEFT) - - def _button_cb(self): - filename = tkinter.filedialog.askopenfilename( - parent=self, - filetypes=[('bin files', '*.bin'), ('all files', '*.*')], - title="Select bin file for %s"%self._what, - initialdir=os.path.dirname(self.get_filename()), - ) - - # open file on your own - if filename: - self._entry.delete(0, tkinter.END) - self._entry.insert(0, filename) - - def get_filename(self): - return self._entry.get() - -class ProgressBar(tkinter.Canvas): - """ - A simple implementation of a progress bar. - Draws rectangle that fills from left to right. - """ - - def __init__(self, root, width=500, height=20): - self._width = width - self._height = height - tkinter.Canvas.__init__(self, root, relief="sunken", borderwidth=2, width=self._width-2, height=self._height-2) - self._last_fill_pixels = None - self.set(0.0) - - def set(self, frac): - """ - Update the progress where fraction is between 0.0 and 1.0 - """ - #determine the number of pixels to draw - fill_pixels = int(round(self._width*frac)) - if fill_pixels == self._last_fill_pixels: return - self._last_fill_pixels = fill_pixels - - #draw a rectangle representing the progress - if frac: self.create_rectangle(0, 0, fill_pixels, self._height, fill="#357EC7") - else: self.create_rectangle(0, 0, self._width, self._height, fill="#E8E8E8") - -class DeviceEntryWidget(tkinter.Frame): - """ - Simple entry widget for getting the network device name. - Combines a label, entry, and helpful text box with hints. - """ - - def __init__(self, root, text=''): - tkinter.Frame.__init__(self, root) - - tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack() - - self._hints = tkinter.Listbox(self) - self._hints_addrs_only = tkinter.Listbox(self) - - self._hints.bind("<<ListboxSelect>>", self._listbox_cb) - self._hints_addrs_only.bind("<<ListboxSelect>>", self._listbox_cb) - - self._reload_cb() - self._hints.pack(expand=tkinter.YES, fill=tkinter.X) - - frame = tkinter.Frame(self) - frame.pack() - - tkinter.Label(frame, text="Network Address:").pack(side=tkinter.LEFT) - self._entry = tkinter.Entry(frame, width=50) - self._entry.insert(tkinter.END, text) - self._entry.pack(side=tkinter.LEFT) - - def _reload_cb(self): - self._hints.delete(0, tkinter.END) - for hint in usrp_n2xx_net_burner.enumerate_devices(): - self._hints.insert(tkinter.END, hint) - self._hints_addrs_only.insert(tkinter.END, hint.split(" (")[0]) - - def _listbox_cb(self, event): - try: - sel = self._hints_addrs_only.get(self._hints.curselection()[0]) - self._entry.delete(0, tkinter.END) - self._entry.insert(0, sel) - except Exception as e: print(e) - - def get_devname(self): - return self._entry.get() - -class SectionLabel(tkinter.Label): - """ - Make a text label with bold font. - """ - - def __init__(self, root, text): - tkinter.Label.__init__(self, root, text=text) - - #set the font bold - f = tkinter.font.Font(font=self['font']) - f['weight'] = 'bold' - self['font'] = f.name - -class USRPN2XXNetBurnerApp(tkinter.Frame): - """ - The top level gui application for the usrp-n2xx network burner. - Creates entry widgets and button with callback to write images. - """ - - def __init__(self, root, addr, fw, fpga): - - tkinter.Frame.__init__(self, root) - - #pack the file entry widgets - SectionLabel(self, text="Select Images").pack(pady=5) - self._fw_img_entry = BinFileEntry(self, "Firmware Image", def_path=fw) - self._fw_img_entry.pack() - self._fpga_img_entry = BinFileEntry(self, "FPGA Image", def_path=fpga) - self._fpga_img_entry.pack() - - #pack the destination entry widget - SectionLabel(self, text="Select Device").pack(pady=5) - self._net_dev_entry = DeviceEntryWidget(self, text=addr) - self._net_dev_entry.pack() - - #the do it button - SectionLabel(self, text="").pack(pady=5) - button = tkinter.Button(self, text="Burn Images", command=self._burn) - self._enable_input = lambda: button.configure(state=tkinter.NORMAL) - self._disable_input = lambda: button.configure(state=tkinter.DISABLED) - button.pack() - - #a progress bar to monitor the status - progress_frame = tkinter.Frame(self) - progress_frame.pack() - self._status = tkinter.StringVar() - tkinter.Label(progress_frame, textvariable=self._status).pack(side=tkinter.LEFT) - self._pbar = ProgressBar(progress_frame) - self._pbar.pack(side=tkinter.RIGHT, expand=True) - - def _burn(self): - #grab strings from the gui - fw = self._fw_img_entry.get_filename() - fpga = self._fpga_img_entry.get_filename() - addr = self._net_dev_entry.get_devname() - - #check input - if not addr: - tkinter.messagebox.showerror('Error:', 'No address specified!') - return - if not fw and not fpga: - tkinter.messagebox.showerror('Error:', 'No images specified!') - return - if fw and not os.path.exists(fw): - tkinter.messagebox.showerror('Error:', 'Firmware image not found!') - return - if fpga and not os.path.exists(fpga): - tkinter.messagebox.showerror('Error:', 'FPGA image not found!') - return - - self._disable_input() - try: - #make a new burner object and attempt the burner operation - burner = usrp_n2xx_net_burner.burner_socket(addr=addr,quiet=False) - - #setup callbacks that update the gui - def status_cb(status): - self._pbar.set(0.0) #status change, reset the progress - self._status.set("%s %s "%(status.title(), image_type)) - self.update() - def progress_cb(progress): - self._pbar.set(progress) - self.update() - - if options.overwrite_safe: - if tkinter.messagebox.askyesno("Overwrite safe images?", "Overwrite safe images! This is ALMOST ALWAYS a terrible idea."): - for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): - burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) - burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=True, check_rev=not options.dont_check_rev) - - if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): - burner.reset_usrp() - else: - for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): - burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) - burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=False, check_rev=not options.dont_check_rev) - - if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): - burner.reset_usrp() - - except Exception as e: - tkinter.messagebox.showerror('Verbose:', 'Error: %s'%str(e)) - - #reset the progress bar - self._pbar.set(0.0) - self._status.set("") - self._enable_input() - -######################################################################## -# main -######################################################################## -if __name__=='__main__': - options = usrp_n2xx_net_burner.get_options() - root = tkinter.Tk() - root.title('USRP-N2XX Net Burner') - USRPN2XXNetBurnerApp(root, addr=options.addr, fw=options.fw, fpga=options.fpga).pack() - root.mainloop() - exit() diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp index 56af3ce4a..9077ef2f6 100644 --- a/host/utils/usrp_n2xx_simple_net_burner.cpp +++ b/host/utils/usrp_n2xx_simple_net_burner.cpp @@ -15,171 +15,11 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <csignal> -#include <iostream> -#include <fstream> -#include <time.h> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> -#include <boost/filesystem.hpp> #include <boost/program_options.hpp> -#include <boost/assign.hpp> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/algorithm/string/erase.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread/thread.hpp> - -#include <uhd/exception.hpp> -#include <uhd/property_tree.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> -#include <uhd/utils/safe_call.hpp> +#include <iostream> -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace boost::algorithm; -using namespace uhd; -using namespace uhd::transport; - -#define UDP_FW_UPDATE_PORT 49154 -#define UDP_MAX_XFER_BYTES 1024 -#define UDP_TIMEOUT 3 -#define UDP_POLL_INTERVAL 0.10 //in seconds -#define USRP2_FW_PROTO_VERSION 7 //should be unused after r6 -#define USRP2_UDP_UPDATE_PORT 49154 -#define FLASH_DATA_PACKET_SIZE 256 -#define FPGA_IMAGE_SIZE_BYTES 1572864 -#define FW_IMAGE_SIZE_BYTES 31744 - -#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000 -#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000 - -#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000 -#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000 - -typedef enum { - UNKNOWN = ' ', - - USRP2_QUERY = 'a', - USRP2_ACK = 'A', - - GET_FLASH_INFO_CMD = 'f', - GET_FLASH_INFO_ACK = 'F', - - ERASE_FLASH_CMD = 'e', - ERASE_FLASH_ACK = 'E', - - CHECK_ERASING_DONE_CMD = 'd', - DONE_ERASING_ACK = 'D', - NOT_DONE_ERASING_ACK = 'B', - - WRITE_FLASH_CMD = 'w', - WRITE_FLASH_ACK = 'W', - - READ_FLASH_CMD = 'r', - READ_FLASH_ACK = 'R', - - RESET_USRP_CMD = 's', - RESET_USRP_ACK = 'S', - - GET_HW_REV_CMD = 'v', - GET_HW_REV_ACK = 'V', - -} usrp2_fw_update_id_t; - -typedef struct { - uint32_t proto_ver; - uint32_t id; - uint32_t seq; - union { - uint32_t ip_addr; - uint32_t hw_rev; - struct { - uint32_t flash_addr; - uint32_t length; - uint8_t data[256]; - } flash_args; - struct { - uint32_t sector_size_bytes; - uint32_t memory_size_bytes; - } flash_info_args; - } data; -} usrp2_fw_update_data_t; - -//Mapping revision numbers to filenames -uhd::dict<uint32_t, std::string> filename_map = boost::assign::map_list_of - (0, "N2XX") - (0xa, "n200_r3") - (0x100a, "n200_r4") - (0x10a, "n210_r3") - (0x110a, "n210_r4") -; - -uint8_t usrp2_update_data_in_mem[udp_simple::mtu]; -uint8_t fpga_image[FPGA_IMAGE_SIZE_BYTES]; -uint8_t fw_image[FW_IMAGE_SIZE_BYTES]; - -/*********************************************************************** - * Signal handlers - **********************************************************************/ -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "USRP-N Series unit will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your USRP-N Series unit will be bricked." << std::endl - << "Refer to http://files.ettus.com/manual/page_usrp2.html#usrp2_loadflash_brick" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -/*********************************************************************** - * List all connected USRP N2XX devices - **********************************************************************/ -void list_usrps(){ - udp_simple::sptr udp_bc_transport; - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - uint32_t hw_rev; - - usrp2_fw_update_data_t usrp2_ack_pkt = usrp2_fw_update_data_t(); - usrp2_ack_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - usrp2_ack_pkt.id = htonx<uint32_t>(USRP2_QUERY); - - std::cout << "Available USRP N2XX devices:" << std::endl; - - //Send UDP packets to all broadcast addresses - BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){ - //Avoid the loopback device - if(if_addrs.inet == boost::asio::ip::address_v4::loopback().to_string()) continue; - udp_bc_transport = udp_simple::make_broadcast(if_addrs.bcast, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt))); - - size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_ACK){ - usrp2_ack_pkt.id = htonx<uint32_t>(GET_HW_REV_CMD); - udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt))); - - size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_HW_REV_ACK){ - hw_rev = ntohl(update_data_in->data.hw_rev); - } - - std::cout << boost::format(" * %s (%s)\n") % udp_bc_transport->get_recv_addr() % filename_map[hw_rev]; - } - } -} /*********************************************************************** * Find USRP N2XX with specified IP address and return type @@ -225,8 +65,7 @@ void print_image_loader_warning(const std::string &fw_path, } std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -234,336 +73,8 @@ void print_image_loader_warning(const std::string &fw_path, << std::endl; } -/*********************************************************************** - * Find USRP N2XX with specified IP address and return type - **********************************************************************/ -uint32_t find_usrp(udp_simple::sptr udp_transport, bool check_rev){ - uint32_t hw_rev; - bool found_it = false; - - // If the user chooses to not care about the rev, simply check - // for the presence of a USRP N2XX. - uint32_t cmd_id = (check_rev) ? GET_HW_REV_CMD - : USRP2_QUERY; - uint32_t ack_id = (check_rev) ? GET_HW_REV_ACK - : USRP2_ACK; - - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - usrp2_fw_update_data_t hw_info_pkt = usrp2_fw_update_data_t(); - hw_info_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - hw_info_pkt.id = htonx<uint32_t>(cmd_id); - udp_transport->send(boost::asio::buffer(&hw_info_pkt, sizeof(hw_info_pkt))); - - //Loop and receive until the timeout - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == ack_id){ - hw_rev = ntohl(update_data_in->data.hw_rev); - if(filename_map.has_key(hw_rev)){ - std::cout << boost::format("Found %s.\n\n") % filename_map[hw_rev]; - found_it = true; - } - else{ - if(check_rev) throw std::runtime_error("Invalid revision found."); - else{ - hw_rev = 0; - std::cout << "Found USRP N2XX." << std::endl; - found_it = true; - } - } - } - if(not found_it) throw std::runtime_error("No USRP N2XX found."); - - return hw_rev; -} - -/*********************************************************************** - * Custom filename validation functions - **********************************************************************/ - -void validate_custom_fpga_file(std::string rev_str, std::string& fpga_path, bool check_rev){ - - //Check for existence of file - if(not fs::exists(fpga_path)) throw std::runtime_error(str(boost::format("No file at specified FPGA path: %s") % fpga_path)); - - //If user cares about revision, use revision string to detect invalid image filename - uhd::fs_path custom_fpga_path(fpga_path); - if(custom_fpga_path.leaf().find(rev_str) == std::string::npos and check_rev){ - throw std::runtime_error(str(boost::format("Invalid FPGA image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.") - % fpga_path % rev_str)); - } -} - -void validate_custom_fw_file(std::string rev_str, std::string& fw_path, bool check_rev){ - - //Check for existence of file - if(not fs::exists(fw_path)) throw std::runtime_error(str(boost::format("No file at specified firmware path: %s") % fw_path)); - - //If user cares about revision, use revision string to detect invalid image filename - uhd::fs_path custom_fw_path(fw_path); - if(custom_fw_path.leaf().find(erase_tail_copy(rev_str,3)) == std::string::npos and check_rev){ - throw std::runtime_error(str(boost::format("Invalid firmware image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.") - % fw_path % erase_tail_copy(rev_str,3))); - } -} - -/*********************************************************************** - * Reading and validating image binaries - **********************************************************************/ - -int read_fpga_image(std::string& fpga_path){ - - //Check size of given image - std::ifstream fpga_file(fpga_path.c_str(), std::ios::binary); - fpga_file.seekg(0, std::ios::end); - size_t fpga_image_size = size_t(fpga_file.tellg()); - if(fpga_image_size > FPGA_IMAGE_SIZE_BYTES){ - throw std::runtime_error(str(boost::format("FPGA image is too large. %d > %d") - % fpga_image_size % FPGA_IMAGE_SIZE_BYTES)); - } - - //Check sequence of bytes in image before reading - uint8_t fpga_test_bytes[63]; - fpga_file.seekg(0, std::ios::beg); - fpga_file.read((char*)fpga_test_bytes,63); - bool is_good = false; - for(int i = 0; i < 63; i++){ - if(fpga_test_bytes[i] == 255) continue; - else if(fpga_test_bytes[i] == 170 and - fpga_test_bytes[i+1] == 153){ - is_good = true; - break; - } - } - if(not is_good) throw std::runtime_error("Not a valid FPGA image."); - - //With image validated, read into utility - fpga_file.seekg(0, std::ios::beg); - fpga_file.read((char*)fpga_image,fpga_image_size); - fpga_file.close(); - - //Return image size - return fpga_image_size; -} - -int read_fw_image(std::string& fw_path){ - - //Check size of given image - std::ifstream fw_file(fw_path.c_str(), std::ios::binary); - fw_file.seekg(0, std::ios::end); - size_t fw_image_size = size_t(fw_file.tellg()); - if(fw_image_size > FW_IMAGE_SIZE_BYTES){ - throw std::runtime_error(str(boost::format("Firmware image is too large. %d > %d") - % fw_image_size % FW_IMAGE_SIZE_BYTES)); - } - - //Check sequence of bytes in image before reading - uint8_t fw_test_bytes[4]; - fw_file.seekg(0, std::ios::beg); - fw_file.read((char*)fw_test_bytes,4); - for(int i = 0; i < 4; i++) if(fw_test_bytes[i] != 11) throw std::runtime_error("Not a valid firmware image."); - - //With image validated, read into utility - fw_file.seekg(0, std::ios::beg); - fw_file.read((char*)fw_image,fw_image_size); - fw_file.close(); - - return fw_image_size; -} - -uint32_t* get_flash_info(std::string& ip_addr){ - - uint32_t *flash_info = new uint32_t[2]; - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - usrp2_fw_update_data_t get_flash_info_pkt = usrp2_fw_update_data_t(); - get_flash_info_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - get_flash_info_pkt.id = htonx<uint32_t>(GET_FLASH_INFO_CMD); - udp_transport->send(boost::asio::buffer(&get_flash_info_pkt, sizeof(get_flash_info_pkt))); - - //Loop and receive until the timeout - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_FLASH_INFO_ACK){ - flash_info[0] = ntohl(update_data_in->data.flash_info_args.sector_size_bytes); - flash_info[1] = ntohl(update_data_in->data.flash_info_args.memory_size_bytes); - } - else if(ntohl(update_data_in->id) != GET_FLASH_INFO_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - - return flash_info; -} - -/*********************************************************************** - * Image burning functions - **********************************************************************/ - -void erase_image(udp_simple::sptr udp_transport, bool is_fw, uint32_t memory_size, bool overwrite_safe){ - - uint32_t image_location_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - uint32_t image_size = is_fw ? FW_IMAGE_SIZE_BYTES - : FPGA_IMAGE_SIZE_BYTES; - - //Making sure this won't attempt to erase past end of device - if((image_location_addr+image_size) > memory_size) throw std::runtime_error("Cannot erase past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t erase_pkt = usrp2_fw_update_data_t(); - erase_pkt.id = htonx<uint32_t>(ERASE_FLASH_CMD); - erase_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - erase_pkt.data.flash_args.flash_addr = htonx<uint32_t>(image_location_addr); - erase_pkt.data.flash_args.length = htonx<uint32_t>(image_size); - - //Begin erasing - udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == ERASE_FLASH_ACK){ - if(is_fw) std::cout << "Erasing firmware image." << std::endl; - else std::cout << "Erasing FPGA image." << std::endl; - } - else if(ntohl(update_data_in->id) != ERASE_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - - //Check for erase completion - erase_pkt.id = htonx<uint32_t>(CHECK_ERASING_DONE_CMD); - while(true){ - udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == DONE_ERASING_ACK){ - std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") - % image_size % image_location_addr; - break; - } - else if(ntohl(update_data_in->id) != NOT_DONE_ERASING_ACK){ - throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") - % ntohl(update_data_in->id))); - } - } -} - -void write_image(udp_simple::sptr udp_transport, bool is_fw, uint8_t* image, - uint32_t memory_size, int image_size, bool overwrite_safe){ - - uint32_t begin_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - uint32_t current_addr = begin_addr; - std::string type = is_fw ? "firmware" : "FPGA"; - - //Making sure this won't attempt to write past end of device - if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot write past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t write_pkt = usrp2_fw_update_data_t(); - write_pkt.id = htonx<uint32_t>(WRITE_FLASH_CMD); - write_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - write_pkt.data.flash_args.length = htonx<uint32_t>(FLASH_DATA_PACKET_SIZE); - - for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){ - //Print progress - std::cout << "\rWriting " << type << " image (" - << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush; - - write_pkt.data.flash_args.flash_addr = htonx<uint32_t>(current_addr); - std::copy(image+(i*FLASH_DATA_PACKET_SIZE), image+((i+1)*FLASH_DATA_PACKET_SIZE), write_pkt.data.flash_args.data); - - udp_transport->send(boost::asio::buffer(&write_pkt, sizeof(write_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != WRITE_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Invalid reply %d from device.") - % ntohl(update_data_in->id))); - } - - current_addr += FLASH_DATA_PACKET_SIZE; - } - std::cout << std::flush << "\rWriting " << type << " image (100%)." << std::endl; - std::cout << boost::format(" * Successfully wrote %d bytes.\n") % image_size; -} - -void verify_image(udp_simple::sptr udp_transport, bool is_fw, uint8_t* image, - uint32_t memory_size, int image_size, bool overwrite_safe){ - - int current_index = 0; - uint32_t begin_addr = is_fw ? overwrite_safe ? SAFE_FW_IMAGE_LOCATION_ADDR - : PROD_FW_IMAGE_LOCATION_ADDR - : overwrite_safe ? SAFE_FPGA_IMAGE_LOCATION_ADDR - : PROD_FPGA_IMAGE_LOCATION_ADDR; - uint32_t current_addr = begin_addr; - std::string type = is_fw ? "firmware" : "FPGA"; - - //Array size needs to be known at runtime, this constant is guaranteed to be larger than any firmware or FPGA image - uint8_t from_usrp[FPGA_IMAGE_SIZE_BYTES]; - - //Making sure this won't attempt to read past end of device - if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot read past end of device."); - - //UDP receive buffer - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Setting up UDP packet - usrp2_fw_update_data_t verify_pkt = usrp2_fw_update_data_t(); - verify_pkt.id = htonx<uint32_t>(READ_FLASH_CMD); - verify_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - verify_pkt.data.flash_args.length = htonx<uint32_t>(FLASH_DATA_PACKET_SIZE); - - for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){ - //Print progress - std::cout << "\rVerifying " << type << " image (" - << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush; - - verify_pkt.data.flash_args.flash_addr = htonx<uint32_t>(current_addr); - - udp_transport->send(boost::asio::buffer(&verify_pkt, sizeof(verify_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != READ_FLASH_ACK){ - throw std::runtime_error(str(boost::format("Invalid reply %d from device.") - % ntohl(update_data_in->id))); - } - for(int j = 0; j < FLASH_DATA_PACKET_SIZE; j++) from_usrp[current_index+j] = update_data_in->data.flash_args.data[j]; - - current_addr += FLASH_DATA_PACKET_SIZE; - current_index += FLASH_DATA_PACKET_SIZE; - } - for(int i = 0; i < image_size; i++) if(from_usrp[i] != image[i]) throw std::runtime_error("Image write failed."); - - std::cout << std::flush << "\rVerifying " << type << " image (100%)." << std::endl; - std::cout << " * Successful." << std::endl; -} - -void reset_usrp(udp_simple::sptr udp_transport){ - - //Set up UDP transport - const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem); - - //Set up UDP packet - usrp2_fw_update_data_t reset_pkt = usrp2_fw_update_data_t(); - reset_pkt.id = htonx<uint32_t>(RESET_USRP_CMD); - reset_pkt.proto_ver = htonx<uint32_t>(USRP2_FW_PROTO_VERSION); - - //Reset USRP - udp_transport->send(boost::asio::buffer(&reset_pkt, sizeof(reset_pkt))); - size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT); - if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == RESET_USRP_ACK){ - throw std::runtime_error("USRP reset failed."); //There should be no response to this UDP packet - } - else std::cout << std::endl << "Resetting USRP." << std::endl; -} - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - +int main(int argc, char *argv[]) +{ //Establish user options std::string fw_path; std::string ip_addr; @@ -586,142 +97,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help") > 0){ - std::cout << boost::format("N2XX Simple Net Burner\n"); - std::cout << boost::format("Automatically detects and burns standard firmware and FPGA images onto USRP N2XX devices.\n"); - std::cout << boost::format("Can optionally take user input for custom images.\n\n"); - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List options - if(vm.count("list")){ - list_usrps(); - return EXIT_SUCCESS; - } - - //Store user options - bool burn_fpga = (vm.count("no-fpga") == 0); - bool burn_fw = (vm.count("no-fw") == 0); - bool use_custom_fpga = (vm.count("fpga") > 0); - bool use_custom_fw = (vm.count("fw") > 0); - bool auto_reboot = (vm.count("auto-reboot") > 0); - bool check_rev = (vm.count("dont-check-rev") == 0); - bool overwrite_safe = (vm.count("overwrite-safe") > 0); - int fpga_image_size = 0; - int fw_image_size = 0; - - //Process options and detect invalid option combinations - if(not burn_fpga && not burn_fw){ - std::cout << "No images will be burned." << std::endl; - return EXIT_FAILURE; - } - if(not check_rev){ - //Without knowing a revision, the utility cannot automatically generate a filepath, so the user - //must specify one. The user must also burn both types of images for consistency. - if(not (burn_fpga and burn_fw)) - throw std::runtime_error("If the --dont-check-rev option is used, both FPGA and firmware images need to be burned."); - if(not (use_custom_fpga and use_custom_fw)) - throw std::runtime_error("If the --dont-check-rev option is used, the user must specify image filepaths."); - } - if(overwrite_safe){ - //If the user specifies overwriting safe images, both image types must be burned for consistency. - if(not (burn_fpga and burn_fw)) - throw std::runtime_error("If the --overwrite-safe option is used, both FPGA and firmware images need to be burned."); - - std::cout << "Are you REALLY sure you want to overwrite the safe images?" << std::endl; - std::cout << "This is ALMOST ALWAYS a terrible idea." << std::endl; - std::cout << "Type \"yes\" to continue, or anything else to quit: " << std::flush; - std::string safe_response; - std::getline(std::cin, safe_response); - if(safe_response != "yes"){ - std::cout << "Exiting." << std::endl; - return EXIT_SUCCESS; - } - else std::cout << std::endl; //Formatting - } - - //Find USRP and establish connection - std::cout << boost::format("Searching for USRP N2XX with IP address %s.\n") % ip_addr; - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT)); - uint32_t hw_rev = find_usrp(udp_transport, check_rev); - - //Check validity of file locations and binaries before attempting burn - std::cout << "Searching for specified images." << std::endl << std::endl; - if(burn_fpga){ - if(use_custom_fpga){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME")); - #endif - validate_custom_fpga_file(filename_map[hw_rev], fpga_path, check_rev); - } - else{ - std::string default_fpga_filename = str(boost::format("usrp_%s_fpga.bin") % filename_map[hw_rev]); - fpga_path = find_image_path(default_fpga_filename); - } - - fpga_image_size = read_fpga_image(fpga_path); - } - if(burn_fw){ - if(use_custom_fw){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME")); - #endif - validate_custom_fw_file(filename_map[hw_rev], fw_path, check_rev); - } - else{ - std::string default_fw_filename = str(boost::format("usrp_%s_fw.bin") % erase_tail_copy(filename_map[hw_rev],3)); - fw_path = find_image_path(default_fw_filename); - } - - fw_image_size = read_fw_image(fw_path); - } - print_image_loader_warning(fw_path, fpga_path, vm); - std::cout << "Will burn the following images:" << std::endl; - if(burn_fw) std::cout << boost::format(" * Firmware: %s\n") % fw_path; - if(burn_fpga) std::cout << boost::format(" * FPGA: %s\n") % fpga_path; - std::cout << std::endl; - - uint32_t* flash_info = get_flash_info(ip_addr); - std::cout << boost::format("Querying %s for flash information.\n") % filename_map[hw_rev]; - std::cout << boost::format(" * Flash size: %3.2f\n") % flash_info[1]; - std::cout << boost::format(" * Sector size: %3.2f\n\n") % flash_info[0]; - - //Burning images - std::signal(SIGINT, &sig_int_handler); - if(burn_fpga){ - erase_image(udp_transport, false, flash_info[1], overwrite_safe); - write_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size, overwrite_safe); - verify_image(udp_transport, false, fpga_image, flash_info[1], fpga_image_size, overwrite_safe); - } - if(burn_fpga and burn_fw) std::cout << std::endl; //Formatting - if(burn_fw){ - erase_image(udp_transport, true, flash_info[1], overwrite_safe); - write_image(udp_transport, true, fw_image, flash_info[1], fw_image_size, overwrite_safe); - verify_image(udp_transport, true, fw_image, flash_info[1], fw_image_size, overwrite_safe); - } - - delete(flash_info); - - //Reset USRP N2XX - bool reset = false; - if(auto_reboot) reset = true; - else{ - std::string user_response = "foo"; - while(user_response != "y" and user_response != "" and user_response != "n"){ - std::cout << std::endl << "Image burning successful. Reset USRP (Y/n)? "; - std::getline(std::cin, user_response); - std::transform(user_response.begin(), user_response.end(), user_response.begin(), ::tolower); - reset = (user_response == "" or user_response == "y"); - } - std::cout << std::endl; //Formatting - } - if(reset) reset_usrp(udp_transport); - - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp index e3de8aad3..8f297865b 100644 --- a/host/utils/usrp_x3xx_fpga_burner.cpp +++ b/host/utils/usrp_x3xx_fpga_burner.cpp @@ -15,188 +15,14 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <csignal> #include <iostream> -#include <map> -#include <fstream> -#include <stdexcept> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <vector> - -#include <boost/foreach.hpp> -#include <boost/asio.hpp> #include <boost/program_options.hpp> -#include <boost/property_tree/ptree.hpp> -#include <boost/property_tree/xml_parser.hpp> -#include <boost/assign.hpp> -#include <stdint.h> -#include <boost/assign/list_of.hpp> #include <boost/format.hpp> -#include <boost/algorithm/string/erase.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread/thread.hpp> - -#include <uhd/exception.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/nirio/niusrprio_session.h> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/device.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/safe_main.hpp> -#include <uhd/utils/safe_call.hpp> - -extern "C" { -#include "cdecode.h" -} - -#define X300_FPGA_BIN_SIZE_BYTES 15877916 -#define X300_FPGA_BIT_MAX_SIZE_BYTES 15878032 -#define X300_FPGA_PROG_UDP_PORT 49157 -#define X300_FLASH_SECTOR_SIZE 131072 -#define X300_PACKET_SIZE_BYTES 256 -#define X300_FPGA_SECTOR_START 32 -#define X300_MAX_RESPONSE_BYTES 128 -#define UDP_TIMEOUT 3 -#define FPGA_LOAD_TIMEOUT 15 -#define X300_FPGA_PROG_FLAGS_ACK 1 -#define X300_FPGA_PROG_FLAGS_ERROR 2 -#define X300_FPGA_PROG_FLAGS_INIT 4 -#define X300_FPGA_PROG_FLAGS_CLEANUP 8 -#define X300_FPGA_PROG_FLAGS_ERASE 16 -#define X300_FPGA_PROG_FLAGS_VERIFY 32 -#define X300_FPGA_PROG_CONFIGURE 64 -#define X300_FPGA_PROG_CONFIG_STATUS 128 - -namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace uhd; -using namespace uhd::transport; - -static int num_ctrl_c = 0; -void sig_int_handler(int){ - num_ctrl_c++; - if(num_ctrl_c == 1){ - std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " - "USRP-X series device will be bricked!" << std::endl - << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; - } - else{ - std::cout << std::endl << "Aborting. Your USRP X-Series device will be bricked." << std::endl - << "http://files.ettus.com/manual/page_usrp_x3x0.html#x3x0_load_fpga_imgs_jtag" << std::endl - << "for details on restoring your device." << std::endl; - exit(EXIT_FAILURE); - } -} - -typedef struct { - uint32_t flags; - uint32_t sector; - uint32_t index; - uint32_t size; - uint16_t data[128]; -} x300_fpga_update_data_t; - -uint8_t x300_data_in_mem[udp_simple::mtu]; -uint8_t intermediary_packet_data[X300_PACKET_SIZE_BYTES]; - -uint8_t bitswap(uint8_t b){ - b = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4); - b = ((b & 0xCC) >> 2) | ((b & 0x33) << 2); - b = ((b & 0xAA) >> 1) | ((b & 0x55) << 1); - - return b; -} - -void list_usrps(){ - device_addrs_t found_devices = device::find(device_addr_t("type=x300"), device::USRP); - - std::cout << "Available X3x0 devices:" << std::endl; - BOOST_FOREACH(const device_addr_t &dev, found_devices){ - std::string dev_string; - if(dev.has_key("addr")){ - dev_string = str(boost::format(" * %s (%s, addr: %s)") - % dev["product"] - % dev["fpga"] - % dev["addr"]); - } - else{ - dev_string = str(boost::format(" * %s (%s, resource: %s)") - % dev["product"] - % dev["fpga"] - % dev["resource"]); - } - std::cout << dev_string << std::endl; - } -} - -device_addr_t find_usrp_with_ethernet(std::string ip_addr, bool output){ - if(output) std::cout << "Attempting to find X3x0 with IP address: " << ip_addr << std::endl; - const device_addr_t dev = device_addr_t(str(boost::format("addr=%s") % ip_addr)); - device_addrs_t found_devices = device::find(dev, device::USRP); - - if(found_devices.size() < 1) { - throw std::runtime_error("Could not find X3x0 with the specified address!"); - } - else if(found_devices.size() > 1) { - throw std::runtime_error("Found multiple X3x0 units with the specified address!"); - } - else { - if(output) std::cout << (boost::format("Found %s (%s).\n\n") - % found_devices[0]["product"] - % found_devices[0]["fpga"]); - } - return found_devices[0]; -} - -device_addr_t find_usrp_with_pcie(std::string resource, bool output){ - if(output) std::cout << "Attempting to find X3x0 with resource: " << resource << std::endl; - const device_addr_t dev = device_addr_t(str(boost::format("resource=%s") % resource)); - device_addrs_t found_devices = device::find(dev, device::USRP); - - if(found_devices.size() < 1) { - throw std::runtime_error("Could not find X3x0 with the specified resource!"); - } - else { - if(output) std::cout << (boost::format("Found %s (%s).\n\n") - % found_devices[0]["product"] - % found_devices[0]["fpga"]); - } - return found_devices[0]; -} - -std::string get_default_image_path(std::string model, std::string image_type){ - std::transform(model.begin(), model.end(), model.begin(), ::tolower); - - std::string image_name = str(boost::format("usrp_%s_fpga_%s.bit") - % model.c_str() % image_type.c_str()); - - return find_image_path(image_name); -} - -void extract_from_lvbitx(std::string lvbitx_path, std::vector<char> &bitstream){ - boost::property_tree::ptree pt; - boost::property_tree::xml_parser::read_xml(lvbitx_path.c_str(), pt, - boost::property_tree::xml_parser::no_comments | - boost::property_tree::xml_parser::trim_whitespace); - std::string const encoded_bitstream(pt.get<std::string>("Bitfile.Bitstream")); - std::vector<char> decoded_bitstream(encoded_bitstream.size()); - - base64_decodestate decode_state; - base64_init_decodestate(&decode_state); - size_t const decoded_size = base64_decode_block(encoded_bitstream.c_str(), - encoded_bitstream.size(), &decoded_bitstream.front(), &decode_state); - decoded_bitstream.resize(decoded_size); - bitstream.swap(decoded_bitstream); -} - -void print_image_loader_warning(const std::string &fpga_path, const po::variables_map &vm){ - +void print_image_loader_warning(const std::string &fpga_path, const po::variables_map &vm) +{ // Newline + indent #ifdef UHD_PLATFORM_WIN32 const std::string nl = " ^\n "; @@ -210,11 +36,9 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable if(vm.count("addr") > 0){ uhd_image_loader += str(boost::format(",addr=%s") % vm["addr"].as<std::string>()); - if(vm.count("configure") > 0){ uhd_image_loader += ",configure"; } - if(vm.count("verify") > 0){ uhd_image_loader += ",verify"; } @@ -251,8 +75,7 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable } std::cout << "************************************************************************************************" << std::endl - << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl - << " this command:" << std::endl + << "ERROR: This utility has been removed in this version of UHD. Use this command:" << std::endl << std::endl << uhd_image_loader << std::endl << std::endl @@ -260,218 +83,17 @@ void print_image_loader_warning(const std::string &fpga_path, const po::variable << std::endl; } -void ethernet_burn(udp_simple::sptr udp_transport, std::string fpga_path, bool verify){ - uint32_t max_size; - std::vector<char> bitstream; - - if(fs::extension(fpga_path) == ".bit") max_size = X300_FPGA_BIT_MAX_SIZE_BYTES; - else max_size = X300_FPGA_BIN_SIZE_BYTES; //Use for both .bin and .lvbitx - - bool is_lvbitx = (fs::extension(fpga_path) == ".lvbitx"); - - size_t fpga_image_size; - FILE* file; - if((file = fopen(fpga_path.c_str(), "rb"))){ - fseek(file, 0, SEEK_END); - if(is_lvbitx){ - extract_from_lvbitx(fpga_path, bitstream); - fpga_image_size = bitstream.size(); - } - else fpga_image_size = ftell(file); - if(fpga_image_size > max_size){ - fclose(file); - throw std::runtime_error(str(boost::format("FPGA size is too large (%d > %d).") - % fpga_image_size % max_size)); - } - rewind(file); - } - else{ - throw std::runtime_error(str(boost::format("Could not find FPGA image at location: %s") - % fpga_path.c_str())); - } - - const x300_fpga_update_data_t *update_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - x300_fpga_update_data_t ack_packet; - ack_packet.flags = htonx<uint32_t>(X300_FPGA_PROG_FLAGS_ACK | X300_FPGA_PROG_FLAGS_INIT); - ack_packet.sector = 0; - ack_packet.size = 0; - ack_packet.index = 0; - memset(ack_packet.data, 0, sizeof(ack_packet.data)); - udp_transport->send(boost::asio::buffer(&ack_packet, sizeof(ack_packet))); - - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT); - if((ntohl(update_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) != X300_FPGA_PROG_FLAGS_ERROR){ - std::cout << "Burning image: " << fpga_path << std::endl; - if(verify) std::cout << "NOTE: Verifying image. Burning will take much longer." << std::endl; - std::cout << std::endl; - } - else{ - throw std::runtime_error("Failed to start image burning! Did you specify the correct IP address? If so, power-cycle the device and try again."); - } - - size_t current_pos = 0; - size_t sectors = fpga_image_size / X300_FLASH_SECTOR_SIZE; - - //Each sector - for(size_t i = 0; i < fpga_image_size; i += X300_FLASH_SECTOR_SIZE){ - - //Print progress percentage at beginning of each sector - std::cout << "\rProgress: " << int(double(i)/double(fpga_image_size)*100) - << "% (" << (i / X300_FLASH_SECTOR_SIZE) << "/" - << sectors << " sectors)" << std::flush; - - //Each packet - for(size_t j = i; (j < fpga_image_size and j < (i+X300_FLASH_SECTOR_SIZE)); j += X300_PACKET_SIZE_BYTES){ - x300_fpga_update_data_t send_packet; - - send_packet.flags = X300_FPGA_PROG_FLAGS_ACK; - if(verify) send_packet.flags |= X300_FPGA_PROG_FLAGS_VERIFY; - if(j == i) send_packet.flags |= X300_FPGA_PROG_FLAGS_ERASE; //Erase the sector before writing - send_packet.flags = htonx<uint32_t>(send_packet.flags); - - send_packet.sector = htonx<uint32_t>(X300_FPGA_SECTOR_START + (i/X300_FLASH_SECTOR_SIZE)); - send_packet.index = htonx<uint32_t>((j % X300_FLASH_SECTOR_SIZE) / 2); - send_packet.size = htonx<uint32_t>(X300_PACKET_SIZE_BYTES / 2); - memset(intermediary_packet_data,0,X300_PACKET_SIZE_BYTES); - memset(send_packet.data,0,X300_PACKET_SIZE_BYTES); - if(!is_lvbitx) current_pos = ftell(file); - - if(current_pos + X300_PACKET_SIZE_BYTES > fpga_image_size){ - if(is_lvbitx){ - memcpy(intermediary_packet_data, (&bitstream[current_pos]), (bitstream.size()-current_pos+1)); - } - else{ - size_t len = fread(intermediary_packet_data, sizeof(uint8_t), (fpga_image_size-current_pos), file); - if(len != (fpga_image_size-current_pos)){ - throw std::runtime_error("Error reading from file!"); - } - } - } - else{ - if(is_lvbitx){ - memcpy(intermediary_packet_data, (&bitstream[current_pos]), X300_PACKET_SIZE_BYTES); - current_pos += X300_PACKET_SIZE_BYTES; - } - else{ - size_t len = fread(intermediary_packet_data, sizeof(uint8_t), X300_PACKET_SIZE_BYTES, file); - if(len != X300_PACKET_SIZE_BYTES){ - throw std::runtime_error("Error reading from file!"); - } - } - } - - for(size_t k = 0; k < X300_PACKET_SIZE_BYTES; k++){ - intermediary_packet_data[k] = bitswap(intermediary_packet_data[k]); - } - - memcpy(send_packet.data, intermediary_packet_data, X300_PACKET_SIZE_BYTES); - - for(size_t k = 0; k < (X300_PACKET_SIZE_BYTES/2); k++){ - send_packet.data[k] = htonx<uint16_t>(send_packet.data[k]); - } - - udp_transport->send(boost::asio::buffer(&send_packet, sizeof(send_packet))); - - if (udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT) == 0) - throw std::runtime_error("Timed out waiting for ACK!"); - - const x300_fpga_update_data_t *update_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(update_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - } - } - fclose(file); - - //Send clean-up signal - x300_fpga_update_data_t cleanup_packet; - cleanup_packet.flags = htonx<uint32_t>(X300_FPGA_PROG_FLAGS_ACK | X300_FPGA_PROG_FLAGS_CLEANUP); - cleanup_packet.sector = 0; - cleanup_packet.size = 0; - cleanup_packet.index = 0; - memset(cleanup_packet.data, 0, sizeof(cleanup_packet.data)); - udp_transport->send(boost::asio::buffer(&cleanup_packet, sizeof(cleanup_packet))); - - if (udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT) == 0) - throw std::runtime_error("Timed out waiting for ACK!"); - const x300_fpga_update_data_t *cleanup_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(cleanup_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - - std::cout << "\rProgress: " << "100% (" << sectors << "/" << sectors << " sectors)" << std::endl; -} - -void pcie_burn(std::string resource, std::string rpc_port, std::string fpga_path) -{ - std::cout << "Burning image: " << fpga_path << std::endl; - std::cout << "This will take 3-10 minutes." << std::endl; - - nirio_status status = NiRio_Status_Success; - - uhd::niusrprio::niusrprio_session fpga_session(resource, rpc_port); - nirio_status_chain(fpga_session.download_bitstream_to_flash(fpga_path), status); - - if(nirio_status_fatal(status)) throw std::runtime_error("Failed to burn FPGA image!"); -} - -bool configure_fpga(udp_simple::sptr udp_transport, std::string ip_addr){ - x300_fpga_update_data_t configure_packet; - configure_packet.flags = htonx<uint32_t>(X300_FPGA_PROG_CONFIGURE | X300_FPGA_PROG_FLAGS_ACK); - configure_packet.sector = 0; - configure_packet.size = 0; - configure_packet.index = 0; - memset(configure_packet.data, 0, sizeof(configure_packet.data)); - udp_transport->send(boost::asio::buffer(&configure_packet, sizeof(configure_packet))); - - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), UDP_TIMEOUT); - const x300_fpga_update_data_t *configure_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - bool successful = false; - - if((ntohl(configure_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) == X300_FPGA_PROG_FLAGS_ERROR){ - throw std::runtime_error("Transfer or data verification failed!"); - } - else{ - std::cout << std::endl << "Waiting for X3x0 to configure FPGA image and reload." << std::endl; - boost::this_thread::sleep(boost::posix_time::milliseconds(5000)); - - x300_fpga_update_data_t config_status_packet; - configure_packet.flags = htonx<uint32_t>(X300_FPGA_PROG_CONFIG_STATUS); - config_status_packet.sector = 0; - config_status_packet.size = 0; - config_status_packet.index = 0; - memset(config_status_packet.data, 0, sizeof(config_status_packet.data)); - for(int i = 0; i < 5; i++){ - udp_transport->send(boost::asio::buffer(&config_status_packet, sizeof(config_status_packet))); - udp_transport->recv(boost::asio::buffer(x300_data_in_mem), 1); - const x300_fpga_update_data_t *config_status_data_in = reinterpret_cast<const x300_fpga_update_data_t *>(x300_data_in_mem); - - if((ntohl(config_status_data_in->flags) & X300_FPGA_PROG_FLAGS_ERROR) != X300_FPGA_PROG_FLAGS_ERROR - and udp_transport->get_recv_addr() == ip_addr){ - successful = true; - break; - } - successful = false; //If it worked, the break would skip this - } - } - return successful; -} - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - memset(intermediary_packet_data, 0, X300_PACKET_SIZE_BYTES); +int main(int argc, char *argv[]){ std::string ip_addr, resource, fpga_path, image_type, rpc_port; po::options_description desc("Allowed options"); desc.add_options() ("help", "Display this help message.") - ("addr", po::value<std::string>(&ip_addr), "Specify an IP address.") + ("addr", po::value<std::string>(&ip_addr)->default_value("1.2.3.4"), "Specify an IP address.") ("resource", po::value<std::string>(&resource), "Specify an NI-RIO resource.") ("rpc-port", po::value<std::string>(&rpc_port)->default_value("5444"), "Specify a port to communicate with the RPC server.") - ("type", po::value<std::string>(&image_type), "Specify an image type (1G, HGS, XGS), leave blank for current type.") - ("fpga-path", po::value<std::string>(&fpga_path), "Specify an FPGA path (overrides --type option).") + ("type", po::value<std::string>(&image_type)->default_value("HG"), "Specify an image type (1G, HG, XG), leave blank for current type.") + ("fpga-path", po::value<std::string>(&fpga_path)->default_value("/path/to/fpga-image.bit"), "Specify an FPGA path (overrides --type option).") ("configure", "Initialize FPGA with image currently burned to flash (Ethernet only).") ("verify", "Verify data downloaded to flash (Ethernet only, download will take much longer)") ("list", "List all available X3x0 devices.") @@ -480,97 +102,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); - //Print help message - if(vm.count("help")){ - std::cout << "USRP X3x0 FPGA Burner" << std::endl << std::endl; - - std::cout << "Burns an FPGA image onto a USRP X300/X310. To burn the image" << std::endl - << "over Ethernet, specify an IP address with the --addr option," << std::endl - << "or to burn over PCIe, specify an NI-RIO resource (ex. RIO0)" << std::endl - << "with the --resource option." << std::endl << std::endl; - - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - //List all available devices - if(vm.count("list")){ - list_usrps(); - return EXIT_SUCCESS; - } - - /* - * The user must specify whether to burn the image over Ethernet or PCI-e. - */ - if(not (vm.count("addr") xor vm.count("resource"))){ - throw std::runtime_error("You must specify addr OR resource!"); - } - - /* - * With settings validated, find X3x0 with specified arguments. - */ - device_addr_t dev = (vm.count("addr")) ? find_usrp_with_ethernet(ip_addr, true) - : find_usrp_with_pcie(resource, true); - - /* - * If custom FPGA path is given, ignore specified type and let FPGA - * figure it out. - */ - if(vm.count("fpga-path")){ - //Expand tilde usage if applicable - #ifndef UHD_PLATFORM_WIN32 - if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME")); - #endif - } - else{ - if(vm.count("type")){ - //Make sure the specified type is 1G, HGS, or XGS - if((image_type != "1G") and (image_type != "HGS") and (image_type != "XGS")){ - throw std::runtime_error("--type must be 1G, HGS, or XGS!"); - } - else fpga_path = get_default_image_path(dev["product"], image_type); - } - else{ - //Use default image of currently present FPGA type - fpga_path = get_default_image_path(dev["product"], dev["fpga"]); - } - } - - /* - * Check validity of image through extension - */ - std::string ext = fs::extension(fpga_path.c_str()); - if(ext != ".bin" and ext != ".bit" and ext != ".lvbitx"){ - throw std::runtime_error("The image filename must end in .bin, .bit, or .lvbitx."); - } - print_image_loader_warning(fpga_path, vm); - std::signal(SIGINT, &sig_int_handler); - if(vm.count("addr")){ - udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(X300_FPGA_PROG_UDP_PORT)); - - ethernet_burn(udp_transport, fpga_path, (vm.count("verify") > 0)); - - if(vm.count("configure")){ - if(configure_fpga(udp_transport, ip_addr)) std::cout << "Successfully configured FPGA!" << std::endl; - else throw std::runtime_error("FPGA configuring failed!"); - } - } - else pcie_burn(resource, rpc_port, fpga_path); - - /* - * Attempt to find USRP after burning - */ - std::cout << std::endl << "Attempting to find device..." << std::flush; - boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); //Sometimes needed for Ethernet to reconnect - device_addr_t found_usrp = (vm.count("addr")) ? find_usrp_with_ethernet(ip_addr, false) - : find_usrp_with_pcie(resource, false); - std::cout << "found!" << std::endl; //If unsuccessful, runtime error would occur in find functions - std::cout << "Successfully burned FPGA image!" << std::endl << std::endl; - - if(vm.count("addr")) std::cout << str(boost::format("Power-cycle the USRP %s to use the new image.") % found_usrp["product"]) << std::endl; - else std::cout << str(boost::format("Power-cycle the USRP %s and reboot your machine to use the new image.") % found_usrp["product"]) << std::endl; - - return EXIT_SUCCESS; + return EXIT_FAILURE; } + |