diff options
author | Ashish Chaudhari <ashish@ettus.com> | 2015-08-10 23:14:20 -0700 |
---|---|---|
committer | Ashish Chaudhari <ashish@ettus.com> | 2015-08-10 23:14:20 -0700 |
commit | b5c81677078f56b3e671ebeaca1e3b803c2f4ef9 (patch) | |
tree | a1b17b4be203331de7e146e94051f26be5a20102 /host/lib | |
parent | 16e149fe6fcc1bc18adea3eeeefad2c7ee93b2e0 (diff) | |
parent | 28327c8e8a810b19da126116d0dc4c26b643baed (diff) | |
download | uhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.tar.gz uhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.tar.bz2 uhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.zip |
Merge branch 'master' into ashish/register_api
Diffstat (limited to 'host/lib')
42 files changed, 3555 insertions, 218 deletions
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 3d4ba8a68..f74af1f29 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -96,6 +96,12 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_BINARY_DIR}/version.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/error_c.cpp + ) +ENDIF(ENABLE_C_API) + ######################################################################## # Add DLL resource file to Windows build ######################################################################## diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp index 65fdcbea2..6e73e9436 100644 --- a/host/lib/convert/convert_common.hpp +++ b/host/lib/convert/convert_common.hpp @@ -86,6 +86,7 @@ typedef float f32_t; typedef boost::int32_t s32_t; typedef boost::int16_t s16_t; typedef boost::int8_t s8_t; +typedef boost::uint8_t u8_t; typedef boost::uint32_t item32_t; diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp index fd6c8497e..d90bb9c94 100644 --- a/host/lib/convert/convert_impl.cpp +++ b/host/lib/convert/convert_impl.cpp @@ -172,6 +172,7 @@ UHD_STATIC_BLOCK(convert_register_item_sizes){ convert::register_bytes_per_item("s32", sizeof(boost::int32_t)); convert::register_bytes_per_item("s16", sizeof(boost::int16_t)); convert::register_bytes_per_item("s8", sizeof(boost::int8_t)); + convert::register_bytes_per_item("u8", sizeof(boost::uint8_t)); //register VITA types convert::register_bytes_per_item("item32", sizeof(boost::int32_t)); diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py index 8090f14bd..4f9eeb747 100644 --- a/host/lib/convert/gen_convert_general.py +++ b/host/lib/convert/gen_convert_general.py @@ -28,26 +28,79 @@ TMPL_HEADER = """ #include <uhd/utils/byteswap.hpp> using namespace uhd::convert; + + +// item32 -> item32: Just a memcpy. No scaling possible. +DECLARE_CONVERTER(item32, 1, item32, 1, PRIORITY_GENERAL) { + const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); + item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + + memcpy(output, input, nsamps * sizeof(item32_t)); +} """ TMPL_CONV_GEN2_ITEM32 = """ -DECLARE_CONVERTER(item32, 1, sc16_item32_${end}, 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(item32, 1, sc16_item32_{end}, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); - for (size_t i = 0; i < nsamps; i++){ - output[i] = ${to_wire}(input[i]); - } -} + for (size_t i = 0; i < nsamps; i++) {{ + output[i] = {to_wire}(input[i]); + }} +}} -DECLARE_CONVERTER(sc16_item32_${end}, 1, item32, 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(sc16_item32_{end}, 1, item32, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); - for (size_t i = 0; i < nsamps; i++){ - output[i] = ${to_host}(input[i]); - } -} + for (size_t i = 0; i < nsamps; i++) {{ + output[i] = {to_host}(input[i]); + }} +}} +""" + +TMPL_CONV_U8 = """ +DECLARE_CONVERTER(u8, 1, u8_item32_{end}, 1, PRIORITY_GENERAL) {{ + const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); + boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); + + // 1) Copy all the 4-byte tuples + size_t n_words = nsamps / 4; + for (size_t i = 0; i < n_words; i++) {{ + output[i] = {to_wire}(input[i]); + }} + // 2) If nsamps was not a multiple of 4, copy the rest by hand + size_t bytes_left = nsamps % 4; + if (bytes_left) {{ + const u8_t *last_input_word = reinterpret_cast<const u8_t *>(&input[n_words]); + u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); + for (size_t k = 0; k < bytes_left; k++) {{ + last_output_word[k] = last_input_word[k]; + }} + output[n_words] = {to_wire}(output[n_words]); + }} +}} + +DECLARE_CONVERTER(u8_item32_{end}, 1, u8, 1, PRIORITY_GENERAL) {{ + const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); + boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); + + // 1) Copy all the 4-byte tuples + size_t n_words = nsamps / 4; + for (size_t i = 0; i < n_words; i++) {{ + output[i] = {to_host}(input[i]); + }} + // 2) If nsamps was not a multiple of 4, copy the rest by hand + size_t bytes_left = nsamps % 4; + if (bytes_left) {{ + boost::uint32_t last_input_word = {to_host}(input[n_words]); + const u8_t *last_input_word_ptr = reinterpret_cast<const u8_t *>(&last_input_word); + u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); + for (size_t k = 0; k < bytes_left; k++) {{ + last_output_word[k] = last_input_word_ptr[k]; + }} + }} +}} """ TMPL_CONV_USRP1_COMPLEX = """ @@ -116,12 +169,19 @@ if __name__ == '__main__': ('be', 'uhd::ntohx', 'uhd::htonx'), ('le', 'uhd::wtohx', 'uhd::htowx'), ): - output += parse_tmpl( - TMPL_CONV_GEN2_ITEM32, + output += TMPL_CONV_GEN2_ITEM32.format( end=end, to_host=to_host, to_wire=to_wire - ) + ) + #generate raw (u8) converters: + for end, to_host, to_wire in ( + ('be', 'uhd::ntohx', 'uhd::htonx'), + ('le', 'uhd::wtohx', 'uhd::htowx'), + ): + output += TMPL_CONV_U8.format( + end=end, to_host=to_host, to_wire=to_wire + ) - #generate complex converters for usrp1 format + #generate complex converters for usrp1 format (requires Cheetah) for width in 1, 2, 4: for cpu_type, do_scale in ( ('fc64', '*scale_factor'), diff --git a/host/lib/error_c.cpp b/host/lib/error_c.cpp new file mode 100644 index 000000000..c3a83eec9 --- /dev/null +++ b/host/lib/error_c.cpp @@ -0,0 +1,40 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/error.h> +#include <uhd/exception.hpp> + +#define MAP_TO_ERROR(exception_type, error_type) \ + if (dynamic_cast<const uhd::exception_type*>(e)) return error_type; + +uhd_error error_from_uhd_exception(const uhd::exception* e){ + MAP_TO_ERROR(index_error, UHD_ERROR_INDEX) + MAP_TO_ERROR(key_error, UHD_ERROR_KEY) + MAP_TO_ERROR(not_implemented_error, UHD_ERROR_NOT_IMPLEMENTED) + MAP_TO_ERROR(usb_error, UHD_ERROR_USB) + MAP_TO_ERROR(io_error, UHD_ERROR_IO) + MAP_TO_ERROR(os_error, UHD_ERROR_OS) + MAP_TO_ERROR(assertion_error, UHD_ERROR_ASSERTION) + MAP_TO_ERROR(lookup_error, UHD_ERROR_LOOKUP) + MAP_TO_ERROR(type_error, UHD_ERROR_TYPE) + MAP_TO_ERROR(value_error, UHD_ERROR_VALUE) + MAP_TO_ERROR(runtime_error, UHD_ERROR_RUNTIME) + MAP_TO_ERROR(environment_error, UHD_ERROR_ENVIRONMENT) + MAP_TO_ERROR(system_error, UHD_ERROR_SYSTEM) + + return UHD_ERROR_EXCEPT; +} diff --git a/host/lib/exception.cpp b/host/lib/exception.cpp index ea056bd3b..a9e36fd15 100644 --- a/host/lib/exception.cpp +++ b/host/lib/exception.cpp @@ -43,3 +43,8 @@ make_exception_impl("EnvironmentError", environment_error, exception) make_exception_impl("IOError", io_error, environment_error) make_exception_impl("OSError", os_error, environment_error) make_exception_impl("SystemError", system_error, exception) + +usb_error::usb_error(int code, const std::string &what): + runtime_error(str(boost::format("%s %d: %s") % "USBError" % code % what)), _code(code) {} +usb_error *usb_error::dynamic_clone(void) const{return new usb_error(*this);} \ +void usb_error::dynamic_throw(void) const{throw *this;} diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 0baf8dc76..f92117a9e 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -71,7 +71,18 @@ private: timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; - libusb_handle_events_timeout(context, &tv); + int ret = libusb_handle_events_timeout(context, &tv); + switch (ret) + { + case LIBUSB_SUCCESS: + case LIBUSB_ERROR_TIMEOUT: + break; + case LIBUSB_ERROR_NO_DEVICE: + throw uhd::io_error(libusb_strerror(LIBUSB_ERROR_NO_DEVICE)); + default: + UHD_MSG(error) << __FUNCTION__ << ": " << libusb_strerror((libusb_error)ret) << std::endl; + break; + } } }; @@ -251,6 +262,21 @@ public: _claimed.push_back(interface); } + void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) + { + int ret; + ret = libusb_clear_halt(this->get(), recv_endpoint | 0x80); + UHD_LOG << "usb device handle: recv endpoint clear: " << libusb_error_name(ret) << std::endl; + ret = libusb_clear_halt(this->get(), send_endpoint | 0x00); + UHD_LOG << "usb device handle: send endpoint clear: " << libusb_error_name(ret) << std::endl; + } + + void reset_device(void) + { + int ret = libusb_reset_device(this->get()); + UHD_LOG << "usb device handle: dev Reset: " << libusb_error_name(ret) << std::endl; + } + private: libusb::device::sptr _dev; //always keep a reference to device libusb_device_handle *_handle; diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index b00946614..2ff1291d9 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -24,6 +24,29 @@ #include <uhd/transport/usb_device_handle.hpp> #include <libusb.h> +//! Define LIBUSB_CALL when its missing (non-windows) +#ifndef LIBUSB_CALL + #define LIBUSB_CALL +#endif /*LIBUSB_CALL*/ + +//! libusb_handle_events_timeout_completed is only in newer API +#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED + #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ + libusb_handle_events_timeout(ctx, tx) +#endif /* HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED */ + +//! libusb_error_name is only in newer API +#ifndef HAVE_LIBUSB_ERROR_NAME + #define libusb_error_name(code) \ + str(boost::format("LIBUSB_ERROR_CODE %d") % code) +#endif /* HAVE_LIBUSB_ERROR_NAME */ + +//! libusb_strerror is only in newer API +#ifndef HAVE_LIBUSB_STRERROR + #define libusb_strerror(code) \ + libusb_error_name(code) +#endif /* HAVE_LIBUSB_STRERROR */ + /*********************************************************************** * Libusb object oriented smart pointer wrappers: * The following wrappers provide allocation and automatic deallocation @@ -135,6 +158,10 @@ namespace libusb { * Control interface: 0 */ virtual void claim_interface(int) = 0; + + virtual void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) = 0; + + virtual void reset_device(void) = 0; }; /*! diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 1ac02d16f..6925e7659 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -43,23 +43,6 @@ using namespace uhd::transport; static const size_t DEFAULT_NUM_XFERS = 16; //num xfers static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes -//! Define LIBUSB_CALL when its missing (non-windows) -#ifndef LIBUSB_CALL - #define LIBUSB_CALL -#endif /*LIBUSB_CALL*/ - -//! libusb_handle_events_timeout_completed is only in newer API -#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED - #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ - libusb_handle_events_timeout(ctx, tx) -#endif - -//! libusb_error_name is only in newer API -#ifndef HAVE_LIBUSB_ERROR_NAME - #define libusb_error_name(code) \ - str(boost::format("LIBUSB_ERROR_CODE %d") % code) -#endif - //! type for sharing the release queue with managed buffers class libusb_zero_copy_mb; typedef boost::shared_ptr<bounded_buffer<libusb_zero_copy_mb *> > mb_queue_sptr; @@ -155,8 +138,9 @@ public: result.is_recv = _is_recv; #endif const int ret = libusb_submit_transfer(_lut); - if (ret != 0) throw uhd::runtime_error(str(boost::format( - "usb %s submit failed: %s") % _name % libusb_error_name(ret))); + if (ret != LIBUSB_SUCCESS) + throw uhd::runtime_error(str(boost::format("usb %s submit failed: %s") + % _name % libusb_strerror((libusb_error)ret))); } template <typename buffer_type> @@ -164,8 +148,9 @@ public: { if (wait_for_completion(timeout)) { - if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::runtime_error(str(boost::format( - "usb %s transfer status: %d") % _name % int(result.status))); + if (result.status != LIBUSB_TRANSFER_COMPLETED) + throw uhd::runtime_error(str(boost::format("usb %s transfer status: %d") + % _name % libusb_error_name(result.status))); result.completed = 0; return make(reinterpret_cast<buffer_type *>(this), _lut->buffer, (_is_recv)? result.actual_length : _frame_size); } @@ -219,7 +204,8 @@ public: _num_frames(num_frames), _frame_size(frame_size), _buffer_pool(buffer_pool::make(_num_frames, _frame_size)), - _enqueued(_num_frames), _released(_num_frames) + _enqueued(_num_frames), _released(_num_frames), + _status(STATUS_RUNNING) { const bool is_recv = (endpoint & 0x80) != 0; const std::string name = str(boost::format("%s%d") % ((is_recv)? "rx" : "tx") % int(endpoint & 0x7f)); @@ -304,18 +290,24 @@ public: UHD_INLINE typename buffer_type::sptr get_buff(double timeout) { typename buffer_type::sptr buff; - libusb_zero_copy_mb *front = NULL; - boost::mutex::scoped_lock lock(_mutex); + + if (_status == STATUS_ERROR) + return buff; + + // Serialize access to buffers + boost::mutex::scoped_lock get_buff_lock(_get_buff_mutex); + + boost::mutex::scoped_lock queue_lock(_queue_mutex); if (_enqueued.empty()) { - _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6))); + _buff_ready_cond.timed_wait(queue_lock, boost::posix_time::microseconds(long(timeout*1e6))); } if (_enqueued.empty()) return buff; - front = _enqueued.front(); + libusb_zero_copy_mb *front = _enqueued.front(); - lock.unlock(); + queue_lock.unlock(); buff = front->get_new<buffer_type>(timeout); - lock.lock(); + queue_lock.lock(); if (buff) _enqueued.pop_front(); this->submit_what_we_can(); @@ -333,28 +325,39 @@ private: buffer_pool::sptr _buffer_pool; std::vector<boost::shared_ptr<libusb_zero_copy_mb> > _mb_pool; - boost::mutex _mutex; - boost::condition_variable _cond; + boost::mutex _queue_mutex; + boost::condition_variable _buff_ready_cond; + boost::mutex _get_buff_mutex; //! why 2 queues? there is room in the future to have > N buffers but only N in flight boost::circular_buffer<libusb_zero_copy_mb *> _enqueued, _released; + enum {STATUS_RUNNING, STATUS_ERROR} _status; + void enqueue_buffer(libusb_zero_copy_mb *mb) { - boost::mutex::scoped_lock l(_mutex); + boost::mutex::scoped_lock l(_queue_mutex); _released.push_back(mb); this->submit_what_we_can(); - l.unlock(); - _cond.notify_one(); + _buff_ready_cond.notify_one(); } void submit_what_we_can(void) { + if (_status == STATUS_ERROR) + return; while (not _released.empty() and not _enqueued.full()) { - _released.front()->submit(); - _enqueued.push_back(_released.front()); - _released.pop_front(); + try { + _released.front()->submit(); + _enqueued.push_back(_released.front()); + _released.pop_front(); + } + catch (uhd::runtime_error& e) + { + _status = STATUS_ERROR; + throw e; + } } } diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index adc7d5585..70fb5b552 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -87,7 +87,10 @@ public: if (wait_for_recv_ready(_sock_fd, timeout)){ _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0); - UHD_ASSERT_THROW(_len > 0); // TODO: Handle case of recv error + if (_len == 0) + throw uhd::io_error("socket closed"); + if (_len < 0) + throw uhd::io_error(str(boost::format("recv error on socket: %s") % strerror(errno))); index++; //advances the caller's buffer return make(this, _mem, size_t(_len)); } @@ -126,6 +129,10 @@ public: boost::this_thread::sleep(boost::posix_time::microseconds(1)); continue; //try to send again } + if (ret == -1) + { + throw uhd::io_error(str(boost::format("send error on socket: %s") % strerror(errno))); + } UHD_ASSERT_THROW(ret == ssize_t(size())); } _claimer.release(); diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index 5e97628f0..891977065 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -94,3 +94,14 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/filters.cpp ${CMAKE_CURRENT_SOURCE_DIR}/byte_vector.cpp ) + +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/device_addrs_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/metadata_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ranges_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sensors_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tune_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_info_c.cpp + ) +ENDIF() diff --git a/host/lib/types/device_addrs_c.cpp b/host/lib/types/device_addrs_c.cpp new file mode 100644 index 000000000..3a24551d3 --- /dev/null +++ b/host/lib/types/device_addrs_c.cpp @@ -0,0 +1,78 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/device_addrs.h> + +uhd_error uhd_device_addrs_make( + uhd_device_addrs_handle *h +){ + UHD_SAFE_C( + (*h) = new uhd_device_addrs_t; + ) +} + +uhd_error uhd_device_addrs_free( + uhd_device_addrs_handle *h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_device_addrs_push_back( + uhd_device_addrs_handle h, + const char* value +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->device_addrs_cpp.push_back(uhd::device_addr_t(value)); + ) +} + +uhd_error uhd_device_addrs_at( + uhd_device_addrs_handle h, + size_t index, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(value_out, '\0', strbuffer_len); + + std::string value_cpp = h->device_addrs_cpp.at(index).to_string(); + strncpy(value_out, value_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_device_addrs_size( + uhd_device_addrs_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->device_addrs_cpp.size(); + ) +} + +uhd_error uhd_device_addrs_last_error( + uhd_device_addrs_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/metadata_c.cpp b/host/lib/types/metadata_c.cpp new file mode 100644 index 000000000..96f43d140 --- /dev/null +++ b/host/lib/types/metadata_c.cpp @@ -0,0 +1,315 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/metadata.h> + +#include <uhd/types/time_spec.hpp> + +#include <string.h> + +/* + * RX metadata + */ + +uhd_error uhd_rx_metadata_make( + uhd_rx_metadata_handle* handle +){ + UHD_SAFE_C( + *handle = new uhd_rx_metadata_t; + ) +} + +uhd_error uhd_rx_metadata_free( + uhd_rx_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_rx_metadata_has_time_spec( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_rx_metadata_time_spec( + uhd_rx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->rx_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_rx_metadata_more_fragments( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.more_fragments; + ) +} + +uhd_error uhd_rx_metadata_fragment_offset( + uhd_rx_metadata_handle h, + size_t *fragment_offset_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *fragment_offset_out = h->rx_metadata_cpp.fragment_offset; + ) +} + +uhd_error uhd_rx_metadata_start_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.start_of_burst; + ) +} + +uhd_error uhd_rx_metadata_end_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.end_of_burst; + ) +} + +uhd_error uhd_rx_metadata_out_of_sequence( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.out_of_sequence; + ) +} + +uhd_error uhd_rx_metadata_to_pp_string( + uhd_rx_metadata_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->rx_metadata_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_rx_metadata_error_code( + uhd_rx_metadata_handle h, + uhd_rx_metadata_error_code_t *error_code_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *error_code_out = uhd_rx_metadata_error_code_t(h->rx_metadata_cpp.error_code); + ) +} + +uhd_error uhd_rx_metadata_strerror( + uhd_rx_metadata_handle h, + char* strerror_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string strerror_cpp = h->rx_metadata_cpp.strerror(); + memset(strerror_out, '\0', strbuffer_len); + strncpy(strerror_out, strerror_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_rx_metadata_last_error( + uhd_rx_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/* + * TX metadata + */ + +uhd_error uhd_tx_metadata_make( + uhd_tx_metadata_handle* handle, + bool has_time_spec, + time_t full_secs, + double frac_secs, + bool start_of_burst, + bool end_of_burst +){ + UHD_SAFE_C( + *handle = new uhd_tx_metadata_t; + (*handle)->tx_metadata_cpp.has_time_spec = has_time_spec; + if(has_time_spec){ + (*handle)->tx_metadata_cpp.time_spec = uhd::time_spec_t(full_secs, frac_secs); + } + (*handle)->tx_metadata_cpp.start_of_burst = start_of_burst; + (*handle)->tx_metadata_cpp.end_of_burst = end_of_burst; + ) +} + +uhd_error uhd_tx_metadata_free( + uhd_tx_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_tx_metadata_has_time_spec( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_tx_metadata_time_spec( + uhd_tx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->tx_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_tx_metadata_start_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.start_of_burst; + ) +} + +uhd_error uhd_tx_metadata_end_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.end_of_burst; + ) +} + +uhd_error uhd_tx_metadata_last_error( + uhd_tx_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/* + * Async metadata + */ + +uhd_error uhd_async_metadata_make( + uhd_async_metadata_handle* handle +){ + UHD_SAFE_C( + *handle = new uhd_async_metadata_t; + ) +} + +uhd_error uhd_async_metadata_free( + uhd_async_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_async_metadata_channel( + uhd_async_metadata_handle h, + size_t *channel_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *channel_out = h->async_metadata_cpp.channel; + ) +} + +uhd_error uhd_async_metadata_has_time_spec( + uhd_async_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->async_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_async_metadata_time_spec( + uhd_async_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->async_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_async_metadata_event_code( + uhd_async_metadata_handle h, + uhd_async_metadata_event_code_t *event_code_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *event_code_out = uhd_async_metadata_event_code_t(h->async_metadata_cpp.event_code); + ) +} + +uhd_error uhd_async_metadata_user_payload( + uhd_async_metadata_handle h, + uint32_t user_payload_out[4] +){ + UHD_SAFE_C_SAVE_ERROR(h, + memcpy(user_payload_out, h->async_metadata_cpp.user_payload, 4*sizeof(uint32_t)); + ) +} + +uhd_error uhd_async_metadata_last_error( + uhd_async_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/ranges_c.cpp b/host/lib/types/ranges_c.cpp new file mode 100644 index 000000000..0c0df24ce --- /dev/null +++ b/host/lib/types/ranges_c.cpp @@ -0,0 +1,162 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/ranges.h> + +#include <string.h> + +/* + * uhd::range_t + */ +uhd_error uhd_range_to_pp_string( + const uhd_range_t *range, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + uhd::range_t range_cpp = uhd_range_c_to_cpp(range); + std::string pp_string_cpp = range_cpp.to_pp_string(); + + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd::range_t uhd_range_c_to_cpp( + const uhd_range_t *range_c +){ + return uhd::range_t(range_c->start, range_c->stop, range_c->step); +} + +void uhd_range_cpp_to_c( + const uhd::range_t &range_cpp, + uhd_range_t *range_c +){ + range_c->start = range_cpp.start(); + range_c->stop = range_cpp.stop(); + range_c->step = range_cpp.step(); +} + +/* + * uhd::meta_range_t + */ +uhd_error uhd_meta_range_make( + uhd_meta_range_handle* h +){ + UHD_SAFE_C( + (*h) = new uhd_meta_range_t; + ) +} + +uhd_error uhd_meta_range_free( + uhd_meta_range_handle* h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_meta_range_start( + uhd_meta_range_handle h, + double *start_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *start_out = h->meta_range_cpp.start(); + ) +} + +uhd_error uhd_meta_range_stop( + uhd_meta_range_handle h, + double *stop_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *stop_out = h->meta_range_cpp.stop(); + ) +} + +uhd_error uhd_meta_range_step( + uhd_meta_range_handle h, + double *step_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *step_out = h->meta_range_cpp.step(); + ) +} + +uhd_error uhd_meta_range_clip( + uhd_meta_range_handle h, + double value, + bool clip_step, + double *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->meta_range_cpp.clip(value, clip_step); + ) +} + +uhd_error uhd_meta_range_size( + uhd_meta_range_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->meta_range_cpp.size(); + ) +} + +uhd_error uhd_meta_range_push_back( + uhd_meta_range_handle h, + const uhd_range_t *range +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->meta_range_cpp.push_back(uhd_range_c_to_cpp(range)); + ) +} + +uhd_error uhd_meta_range_at( + uhd_meta_range_handle h, + size_t num, + uhd_range_t *range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd_range_cpp_to_c(h->meta_range_cpp.at(num), + range_out); + ) +} + +uhd_error uhd_meta_range_to_pp_string( + uhd_meta_range_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->meta_range_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_meta_range_last_error( + uhd_meta_range_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/sensors_c.cpp b/host/lib/types/sensors_c.cpp new file mode 100644 index 000000000..f1976c102 --- /dev/null +++ b/host/lib/types/sensors_c.cpp @@ -0,0 +1,228 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/sensors.h> + +#include <boost/lexical_cast.hpp> + +#include <stdexcept> +#include <string.h> +#include <string> + +uhd_error uhd_sensor_value_make_from_bool( + uhd_sensor_value_handle* h, + const char* name, + bool value, + const char* utrue, + const char* ufalse +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + utrue, + ufalse); + ) +} + +uhd_error uhd_sensor_value_make_from_int( + uhd_sensor_value_handle* h, + const char* name, + int value, + const char* unit, + const char* formatter +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + std::string fmt(formatter); + if(fmt.empty()){ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + } + else{ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit, + fmt); + } + ) +} + +uhd_error uhd_sensor_value_make_from_realnum( + uhd_sensor_value_handle* h, + const char* name, + double value, + const char* unit, + const char* formatter +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + std::string fmt(formatter); + if(fmt.empty()){ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + } + else{ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit, + fmt); + } + ) +} + +uhd_error uhd_sensor_value_make_from_string( + uhd_sensor_value_handle* h, + const char* name, + const char* value, + const char* unit +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + ) +} + +uhd_error uhd_sensor_value_free( + uhd_sensor_value_handle *h +){ + UHD_SAFE_C( + delete (*h)->sensor_value_cpp; + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_sensor_value_to_bool( + uhd_sensor_value_handle h, + bool *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_bool(); + ) +} + +uhd_error uhd_sensor_value_to_int( + uhd_sensor_value_handle h, + int *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_int(); + ) +} + +uhd_error uhd_sensor_value_to_realnum( + uhd_sensor_value_handle h, + double *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_real(); + ) +} + +uhd_error uhd_sensor_value_name( + uhd_sensor_value_handle h, + char* name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(name_out, '\0', strbuffer_len); + strncpy(name_out, h->sensor_value_cpp->name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_value( + uhd_sensor_value_handle h, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(value_out, '\0', strbuffer_len); + strncpy(value_out, h->sensor_value_cpp->value.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_unit( + uhd_sensor_value_handle h, + char* unit_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(unit_out, '\0', strbuffer_len); + strncpy(unit_out, h->sensor_value_cpp->unit.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_data_type( + uhd_sensor_value_handle h, + uhd_sensor_value_data_type_t *data_type_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *data_type_out = uhd_sensor_value_data_type_t(h->sensor_value_cpp->type); + ) +} + +uhd_error uhd_sensor_value_to_pp_string( + uhd_sensor_value_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->sensor_value_cpp->to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_last_error( + uhd_sensor_value_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/tune_c.cpp b/host/lib/types/tune_c.cpp new file mode 100644 index 000000000..c62935cb8 --- /dev/null +++ b/host/lib/types/tune_c.cpp @@ -0,0 +1,76 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/tune_request.h> +#include <uhd/types/tune_result.h> + +#include <boost/format.hpp> + +#include <cstdlib> +#include <cstring> +#include <iostream> + +/* + * Tune request + */ + +uhd::tune_request_t uhd_tune_request_c_to_cpp(uhd_tune_request_t *tune_request_c){ + uhd::tune_request_t tune_request_cpp; + + tune_request_cpp.target_freq = tune_request_c->target_freq; + tune_request_cpp.rf_freq_policy = uhd::tune_request_t::policy_t(tune_request_c->rf_freq_policy); + tune_request_cpp.rf_freq = tune_request_c->rf_freq; + tune_request_cpp.dsp_freq_policy = uhd::tune_request_t::policy_t(tune_request_c->dsp_freq_policy); + tune_request_cpp.dsp_freq = tune_request_c->dsp_freq; + + std::string args_cpp = (tune_request_c->args) ? tune_request_c->args : std::string(""); + tune_request_cpp.args = uhd::device_addr_t(args_cpp); + + return tune_request_cpp; +} + +/* + * Tune result + */ + +void uhd_tune_result_to_pp_string(uhd_tune_result_t *tune_result_c, + char* pp_string_out, size_t strbuffer_len){ + std::string pp_string_cpp = uhd_tune_result_c_to_cpp(tune_result_c).to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); +} + +uhd::tune_result_t uhd_tune_result_c_to_cpp(uhd_tune_result_t *tune_result_c){ + uhd::tune_result_t tune_result_cpp; + + tune_result_cpp.clipped_rf_freq = tune_result_c->clipped_rf_freq; + tune_result_cpp.target_rf_freq = tune_result_c->target_rf_freq; + tune_result_cpp.actual_rf_freq = tune_result_c->actual_rf_freq; + tune_result_cpp.target_dsp_freq = tune_result_c->target_dsp_freq; + tune_result_cpp.actual_dsp_freq = tune_result_c->actual_dsp_freq; + + return tune_result_cpp; +} + +void uhd_tune_result_cpp_to_c(const uhd::tune_result_t &tune_result_cpp, + uhd_tune_result_t *tune_result_c){ + tune_result_c->clipped_rf_freq = tune_result_cpp.clipped_rf_freq; + tune_result_c->target_rf_freq = tune_result_cpp.target_rf_freq; + tune_result_c->actual_rf_freq = tune_result_cpp.actual_rf_freq; + tune_result_c->target_dsp_freq = tune_result_cpp.target_dsp_freq; + tune_result_c->actual_dsp_freq = tune_result_cpp.actual_dsp_freq; +} diff --git a/host/lib/types/usrp_info_c.cpp b/host/lib/types/usrp_info_c.cpp new file mode 100644 index 000000000..77354d901 --- /dev/null +++ b/host/lib/types/usrp_info_c.cpp @@ -0,0 +1,44 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/types/usrp_info.h> + +uhd_error uhd_usrp_rx_info_free(uhd_usrp_rx_info_t *rx_info){ + free(rx_info->mboard_id); + free(rx_info->mboard_name); + free(rx_info->mboard_serial); + free(rx_info->rx_id); + free(rx_info->rx_subdev_name); + free(rx_info->rx_subdev_spec); + free(rx_info->rx_serial); + free(rx_info->rx_antenna); + + return UHD_ERROR_NONE; +} + +uhd_error uhd_usrp_tx_info_free(uhd_usrp_tx_info_t *tx_info){ + free(tx_info->mboard_id); + free(tx_info->mboard_name); + free(tx_info->mboard_serial); + free(tx_info->tx_id); + free(tx_info->tx_subdev_name); + free(tx_info->tx_subdev_spec); + free(tx_info->tx_serial); + free(tx_info->tx_antenna); + + return UHD_ERROR_NONE; +} diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index ce913aaf6..e01e5e09d 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2015 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 @@ -34,6 +34,15 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/dboard_eeprom_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_c.cpp + ) +ENDIF(ENABLE_C_API) + LIBUHD_REGISTER_COMPONENT("GPSD" ENABLE_GPSD OFF "ENABLE_LIBUHD;ENABLE_GPSD;LIBGPS_FOUND" OFF) IF(ENABLE_GPSD) diff --git a/host/lib/usrp/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp index 87010244c..9eaeeff63 100644 --- a/host/lib/usrp/b200/b200_image_loader.cpp +++ b/host/lib/usrp/b200/b200_image_loader.cpp @@ -40,27 +40,50 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t & bool user_specified){ std::vector<usb_device_handle::sptr> dev_handles = get_b200_device_handles(image_loader_args.args); + std::vector<usb_device_handle::sptr> applicable_dev_handles; b200_iface::sptr iface; + mboard_eeprom_t eeprom; // Internal use if(dev_handles.size() > 0){ BOOST_FOREACH(usb_device_handle::sptr dev_handle, dev_handles){ if(dev_handle->firmware_loaded()){ iface = b200_iface::make(usb_control::make(dev_handle,0)); - mb_eeprom = mboard_eeprom_t(*iface, "B200"); + eeprom = mboard_eeprom_t(*iface, "B200"); if(user_specified){ if(image_loader_args.args.has_key("serial") and - mb_eeprom.get("serial") != image_loader_args.args.get("serial")){ + eeprom.get("serial") != image_loader_args.args.get("serial")){ continue; } if(image_loader_args.args.has_key("name") and - mb_eeprom.get("name") != image_loader_args.args.get("name")){ + eeprom.get("name") != image_loader_args.args.get("name")){ continue; } - return iface; + applicable_dev_handles.push_back(dev_handle); } - else return iface; // Just return first found + else applicable_dev_handles.push_back(dev_handle); } } + + // At this point, we should have a single B2XX + if(applicable_dev_handles.size() == 1){ + mb_eeprom = eeprom; + return iface; + } + else if(applicable_dev_handles.size() > 1){ + std::string err_msg = "Could not resolve given args to a single B2XX device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(usb_device_handle::sptr dev_handle, applicable_dev_handles){ + eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200"); + err_msg += str(boost::format(" * %s (serial=%s)\n") + % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX") + % mb_eeprom.get("serial")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } } // No applicable devices found, return empty sptr so we can exit diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index b45529c1a..f5129bc24 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -37,6 +37,8 @@ #include <ctime> #include <cmath> +#include "../../transport/libusb1_base.hpp" + using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; @@ -125,8 +127,7 @@ static device_addrs_t b200_find(const device_addr_t &hint) // so that re-enumeration after fw load can occur successfully. // This requirement is a courtesy of libusb1.0 on windows. size_t found = 0; - std::vector<usb_device_handle::sptr> b200_device_handles = get_b200_device_handles(hint); - BOOST_FOREACH(usb_device_handle::sptr handle, b200_device_handles) { + BOOST_FOREACH(usb_device_handle::sptr handle, get_b200_device_handles(hint)) { //extract the firmware path for the b200 std::string b200_fw_image; try{ @@ -157,7 +158,7 @@ static device_addrs_t b200_find(const device_addr_t &hint) //search for the device until found or timeout while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0) { - BOOST_FOREACH(usb_device_handle::sptr handle, b200_device_handles) + BOOST_FOREACH(usb_device_handle::sptr handle, get_b200_device_handles(hint)) { usb_control::sptr control; try{control = usb_control::make(handle, 0);} @@ -195,7 +196,24 @@ static device_addrs_t b200_find(const device_addr_t &hint) **********************************************************************/ static device::sptr b200_make(const device_addr_t &device_addr) { - return device::sptr(new b200_impl(device_addr)); + uhd::transport::usb_device_handle::sptr handle; + + // We try twice, because the first time, the link might be in a bad state + // and we might need to reset the link, but if that didn't help, trying + // a third time is pointless. + try { + return device::sptr(new b200_impl(device_addr, handle)); + } + catch (const uhd::usb_error &e) { + libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( + boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() + )); + dev_handle->clear_endpoints(B200_USB_CTRL_RECV_ENDPOINT, B200_USB_CTRL_SEND_ENDPOINT); + dev_handle->clear_endpoints(B200_USB_DATA_RECV_ENDPOINT, B200_USB_DATA_SEND_ENDPOINT); + dev_handle->reset_device(); + } + + return device::sptr(new b200_impl(device_addr, handle)); } UHD_STATIC_BLOCK(register_b200_device) @@ -206,7 +224,7 @@ UHD_STATIC_BLOCK(register_b200_device) /*********************************************************************** * Structors **********************************************************************/ -b200_impl::b200_impl(const device_addr_t &device_addr) : +b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::sptr &handle) : _revision(0), _tick_rate(0.0) // Forces a clock initialization at startup { @@ -263,7 +281,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list); //locate the matching handle in the device list - usb_device_handle::sptr handle; BOOST_FOREACH(usb_device_handle::sptr dev_handle, device_list) { if (dev_handle->get_serial() == device_addr["serial"]){ handle = dev_handle; @@ -361,10 +378,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : ctrl_xport_args["send_frame_size"] = min_frame_size; ctrl_xport_args["num_send_frames"] = "16"; + // This may throw a uhd::usb_error, which will be caught by b200_make(). _ctrl_transport = usb_zero_copy::make( handle, - 4, 8, //interface, endpoint - 3, 4, //interface, endpoint + B200_USB_CTRL_RECV_INTERFACE, B200_USB_CTRL_RECV_ENDPOINT, //interface, endpoint + B200_USB_CTRL_SEND_INTERFACE, B200_USB_CTRL_SEND_ENDPOINT, //interface, endpoint ctrl_xport_args ); while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport @@ -443,10 +461,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "8192"); data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); + // This may throw a uhd::usb_error, which will be caught by b200_make(). _data_transport = usb_zero_copy::make( handle, // identifier - 2, 6, // IN interface, endpoint - 1, 2, // OUT interface, endpoint + B200_USB_DATA_RECV_INTERFACE, B200_USB_DATA_RECV_ENDPOINT, //interface, endpoint + B200_USB_DATA_SEND_INTERFACE, B200_USB_DATA_SEND_ENDPOINT, //interface, endpoint data_xport_args // param hints ); while (_data_transport->get_recv_buff(0.0)){} //flush ctrl xport diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 52ecb98f2..cbd51426d 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -78,6 +78,16 @@ static const boost::uint32_t B200_RX_GPS_UART_SID = FLIP_SID(B200_TX_GPS_UART_SI static const boost::uint32_t B200_LOCAL_CTRL_SID = 0x00000040; static const boost::uint32_t B200_LOCAL_RESP_SID = FLIP_SID(B200_LOCAL_CTRL_SID); +static const unsigned char B200_USB_CTRL_RECV_INTERFACE = 4; +static const unsigned char B200_USB_CTRL_RECV_ENDPOINT = 8; +static const unsigned char B200_USB_CTRL_SEND_INTERFACE = 3; +static const unsigned char B200_USB_CTRL_SEND_ENDPOINT = 4; + +static const unsigned char B200_USB_DATA_RECV_INTERFACE = 2; +static const unsigned char B200_USB_DATA_RECV_ENDPOINT = 6; +static const unsigned char B200_USB_DATA_SEND_INTERFACE = 1; +static const unsigned char B200_USB_DATA_SEND_ENDPOINT = 2; + /* * VID/PID pairs for all B2xx products */ @@ -96,7 +106,7 @@ class b200_impl : public uhd::device { public: //structors - b200_impl(const uhd::device_addr_t &); + b200_impl(const uhd::device_addr_t &, uhd::transport::usb_device_handle::sptr &handle); ~b200_impl(void); //the io interface diff --git a/host/lib/usrp/common/ad936x_manager.cpp b/host/lib/usrp/common/ad936x_manager.cpp index b060880cd..8c8897803 100644 --- a/host/lib/usrp/common/ad936x_manager.cpp +++ b/host/lib/usrp/common/ad936x_manager.cpp @@ -34,7 +34,7 @@ const uint32_t ad936x_manager::DEFAULT_DECIM = 128; const uint32_t ad936x_manager::DEFAULT_INTERP = 128; const bool ad936x_manager::DEFAULT_AUTO_DC_OFFSET = true; const bool ad936x_manager::DEFAULT_AUTO_IQ_BALANCE = true; -const bool ad936x_manager::DEFAULT_AGC_ENABLE = true; +const bool ad936x_manager::DEFAULT_AGC_ENABLE = false; class ad936x_manager_impl : public ad936x_manager { diff --git a/host/lib/usrp/dboard_eeprom_c.cpp b/host/lib/usrp/dboard_eeprom_c.cpp new file mode 100644 index 000000000..e3ef4933f --- /dev/null +++ b/host/lib/usrp/dboard_eeprom_c.cpp @@ -0,0 +1,109 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/usrp/dboard_eeprom.h> +#include <uhd/error.h> + +#include <boost/lexical_cast.hpp> + +#include <string.h> + +uhd_error uhd_dboard_eeprom_make( + uhd_dboard_eeprom_handle* h +){ + UHD_SAFE_C( + *h = new uhd_dboard_eeprom_t; + ) +} + +uhd_error uhd_dboard_eeprom_free( + uhd_dboard_eeprom_handle* h +){ + UHD_SAFE_C( + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_dboard_eeprom_get_id( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string dboard_id_cpp = h->dboard_eeprom_cpp.id.to_string(); + strncpy(id_out, dboard_id_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_dboard_eeprom_set_id( + uhd_dboard_eeprom_handle h, + const char* id +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.id = uhd::usrp::dboard_id_t::from_string(id); + ) +} + +uhd_error uhd_dboard_eeprom_get_serial( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string dboard_serial_cpp = h->dboard_eeprom_cpp.serial; + strncpy(id_out, dboard_serial_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_dboard_eeprom_set_serial( + uhd_dboard_eeprom_handle h, + const char* serial +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.serial = serial; + ) +} + +uhd_error uhd_dboard_eeprom_get_revision( + uhd_dboard_eeprom_handle h, + int* revision_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *revision_out = boost::lexical_cast<int>(h->dboard_eeprom_cpp.revision); + ) +} + +uhd_error uhd_dboard_eeprom_set_revision( + uhd_dboard_eeprom_handle h, + int revision +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.revision = boost::lexical_cast<std::string>(revision); + ) +} + +uhd_error uhd_dboard_eeprom_last_error( + uhd_dboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/usrp/e300/CMakeLists.txt b/host/lib/usrp/e300/CMakeLists.txt index 26e34294a..ae817c620 100644 --- a/host/lib/usrp/e300/CMakeLists.txt +++ b/host/lib/usrp/e300/CMakeLists.txt @@ -42,14 +42,14 @@ IF(ENABLE_E300) ${CMAKE_CURRENT_SOURCE_DIR}/e300_remote_codec_ctrl.cpp ) LIBUHD_APPEND_SOURCES(${E300_SOURCES}) - IF(UDEV_FOUND) + IF(UDEV_FOUND AND NOT E300_FORCE_NETWORK) INCLUDE_DIRECTORIES(${UDEV_INCLUDE_DIR}) LIBUHD_APPEND_LIBS(${UDEV_LIBS}) SET_SOURCE_FILES_PROPERTIES( ${E300_SOURCES} PROPERTIES COMPILE_DEFINITIONS "E300_NATIVE=1" ) - ENDIF(UDEV_FOUND) + ENDIF(UDEV_FOUND AND NOT E300_FORCE_NETWORK) IF(ENABLE_GPSD) SET_SOURCE_FILES_PROPERTIES( diff --git a/host/lib/usrp/e300/e300_common.cpp b/host/lib/usrp/e300/e300_common.cpp index 29117e21f..216713bc6 100644 --- a/host/lib/usrp/e300/e300_common.cpp +++ b/host/lib/usrp/e300/e300_common.cpp @@ -29,6 +29,7 @@ #include <fstream> #include <string> +#ifdef E300_NATIVE namespace uhd { namespace usrp { namespace e300 { namespace common { @@ -90,3 +91,18 @@ UHD_STATIC_BLOCK(register_e300_image_loader) { } }}} + +#else +namespace uhd { namespace usrp { namespace e300 { + +namespace common { + +void load_fpga_image(const std::string&) +{ + throw uhd::assertion_error("load_fpga_image() !E300_NATIVE"); +} + +} + +}}} +#endif diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 6eb63c786..5bef783f6 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -505,14 +505,14 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) this->_setup_radio(instance); // Radio 0 loopback through AD9361 - _codec_mgr->loopback_self_test(_radio_perifs[0].ctrl, TOREG(SR_CODEC_IDLE), RB64_CODEC_READBACK); + _codec_mgr->loopback_self_test(_radio_perifs[0].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); // Radio 1 loopback through AD9361 - _codec_mgr->loopback_self_test(_radio_perifs[1].ctrl, TOREG(SR_CODEC_IDLE), RB64_CODEC_READBACK); + _codec_mgr->loopback_self_test(_radio_perifs[1].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); //////////////////////////////////////////////////////////////////// // internal gpios //////////////////////////////////////////////////////////////////// - gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); + gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second) @@ -749,8 +749,8 @@ void e300_impl::_register_loopback_self_test(wb_iface::sptr iface) for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); - iface->poke32(TOREG(SR_TEST), boost::uint32_t(hash)); - test_fail = iface->peek32(RB32_TEST) != boost::uint32_t(hash); + iface->poke32(radio::sr_addr(radio::TEST), boost::uint32_t(hash)); + test_fail = iface->peek32(radio::RB32_TEST) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; @@ -998,20 +998,20 @@ void e300_impl::_setup_radio(const size_t dspno) //////////////////////////////////////////////////////////////////// // Set up peripherals //////////////////////////////////////////////////////////////////// - perif.atr = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_GPIO)); - perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); + perif.atr = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::GPIO)); + perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); perif.rx_fe->set_iq_balance(rx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); + perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::TX_FRONT)); perif.tx_fe->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.tx_fe->set_iq_balance(tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); - perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP)); + perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); + perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever perif.ddc->set_freq(e300::DEFAULT_DDC_FREQ); - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); - perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever perif.duc->set_freq(e300::DEFAULT_DUC_FREQ); @@ -1019,9 +1019,9 @@ void e300_impl::_setup_radio(const size_t dspno) // create time control objects //////////////////////////////////////////////////////////////////// time_core_3000::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_now = RB64_TIME_NOW; - time64_rb_bases.rb_pps = RB64_TIME_PPS; - perif.time64 = time_core_3000::make(perif.ctrl, TOREG(SR_TIME), time64_rb_bases); + time64_rb_bases.rb_now = radio::RB64_TIME_NOW; + time64_rb_bases.rb_pps = radio::RB64_TIME_PPS; + perif.time64 = time_core_3000::make(perif.ctrl, radio::sr_addr(radio::TIME), time64_rb_bases); //////////////////////////////////////////////////////////////////// // front end corrections @@ -1074,12 +1074,9 @@ void e300_impl::_setup_radio(const size_t dspno) _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, dir == TX_DIRECTION)) ; - - // Network mode currently doesn't support the filter API, so - // prevent it from using it: - if (_xport_path != AXI) { - _tree->remove(rf_fe_path / "filters"); - } + _tree->access<double>(rf_fe_path / "freq" / "value") + .subscribe(boost::bind(&e300_impl::_update_fe_lo_freq, this, key, _1)) + ; // Antenna Setup if (dir == RX_DIRECTION) { diff --git a/host/lib/usrp/e300/e300_regs.hpp b/host/lib/usrp/e300/e300_regs.hpp index 5736ebfd4..846c759a4 100644 --- a/host/lib/usrp/e300/e300_regs.hpp +++ b/host/lib/usrp/e300/e300_regs.hpp @@ -18,36 +18,48 @@ #ifndef INCLUDED_E300_REGS_HPP #define INCLUDED_E300_REGS_HPP -#include <boost/cstdint.hpp> +#include <stdint.h> +#include <uhd/config.hpp> -#define TOREG(x) ((x)*4) +namespace uhd { namespace usrp { namespace e300 { namespace radio { -#define localparam static const int +static UHD_INLINE uint32_t sr_addr(const uint32_t offset) +{ + return offset * 4; +} + +static const uint32_t DACSYNC = 5; +static const uint32_t LOOPBACK = 6; +static const uint32_t TEST = 7; +static const uint32_t SPI = 8; +static const uint32_t GPIO = 16; +static const uint32_t MISC_OUTS = 24; +static const uint32_t READBACK = 32; +static const uint32_t TX_CTRL = 64; +static const uint32_t RX_CTRL = 96; +static const uint32_t TIME = 128; +static const uint32_t RX_DSP = 144; +static const uint32_t TX_DSP = 184; +static const uint32_t LEDS = 195; +static const uint32_t FP_GPIO = 200; +static const uint32_t RX_FRONT = 208; +static const uint32_t TX_FRONT = 216; +static const uint32_t CODEC_IDLE = 250; -localparam SR_TEST = 7; -localparam SR_SPI = 8; -localparam SR_GPIO = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK = 32; -localparam SR_TX_CTRL = 64; -localparam SR_RX_CTRL = 96; -localparam SR_TIME = 128; -localparam SR_RX_DSP = 144; -localparam SR_TX_DSP = 184; -localparam SR_LEDS = 195; -localparam SR_FP_GPIO = 200; -localparam SR_RX_FRONT = 208; -localparam SR_TX_FRONT = 216; -localparam SR_CODEC_IDLE = 250; +static const uint32_t RB32_GPIO = 0; +static const uint32_t RB32_SPI = 4; +static const uint32_t RB64_TIME_NOW = 8; +static const uint32_t RB64_TIME_PPS = 16; +static const uint32_t RB32_TEST = 24; +static const uint32_t RB32_RX = 28; +static const uint32_t RB32_FP_GPIO = 32; +static const uint32_t RB32_MISC_INS = 36; +static const uint32_t RB64_CODEC_READBACK = 40; +static const uint32_t RB32_RADIO_NUM = 48; +}}}} // namespace -localparam RB32_SPI = 4; -localparam RB64_TIME_NOW = 8; -localparam RB64_TIME_PPS = 16; -localparam RB32_TEST = 24; -localparam RB32_FP_GPIO = 32; -localparam RB64_CODEC_READBACK = 40; -localparam RB32_RADIO_NUM = 48; +#define localparam static const int localparam ST_RX_ENABLE = 20; localparam ST_TX_ENABLE = 19; diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index 9708634dd..1e0895393 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -227,7 +227,7 @@ public: //! List all available filters by name std::vector<std::string> get_filter_names(const std::string &) { - UHD_THROW_INVALID_CODE_PATH(); + return std::vector<std::string>(); } //! Return a list of all filters @@ -239,7 +239,7 @@ public: //! Write back a filter void set_filter(const std::string &, const std::string &, const filter_info_base::sptr) { - UHD_THROW_INVALID_CODE_PATH(); + UHD_MSG(warning) << "Attempting to set filter on E300 in network mode." << std::endl; } private: diff --git a/host/lib/usrp/mboard_eeprom_c.cpp b/host/lib/usrp/mboard_eeprom_c.cpp new file mode 100644 index 000000000..8d5c069b9 --- /dev/null +++ b/host/lib/usrp/mboard_eeprom_c.cpp @@ -0,0 +1,72 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/usrp/mboard_eeprom.h> + +#include <uhd/exception.hpp> + +#include <string.h> + +uhd_error uhd_mboard_eeprom_make( + uhd_mboard_eeprom_handle* h +){ + UHD_SAFE_C( + *h = new uhd_mboard_eeprom_t; + ) +} + +uhd_error uhd_mboard_eeprom_free( + uhd_mboard_eeprom_handle* h +){ + UHD_SAFE_C( + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_mboard_eeprom_get_value( + uhd_mboard_eeprom_handle h, + const char* key, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string value_cpp = h->mboard_eeprom_cpp.get(key); + strncpy(value_out, value_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_mboard_eeprom_set_value( + uhd_mboard_eeprom_handle h, + const char* key, + const char* value +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->mboard_eeprom_cpp[key] = value; + ) +} + +uhd_error uhd_mboard_eeprom_last_error( + uhd_mboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/usrp/subdev_spec_c.cpp b/host/lib/usrp/subdev_spec_c.cpp new file mode 100644 index 000000000..2c9c20506 --- /dev/null +++ b/host/lib/usrp/subdev_spec_c.cpp @@ -0,0 +1,149 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/usrp/subdev_spec.h> + +#include <string.h> + +uhd_error uhd_subdev_spec_pair_free( + uhd_subdev_spec_pair_t *subdev_spec_pair +){ + UHD_SAFE_C( + if(subdev_spec_pair->db_name){ + free(subdev_spec_pair->db_name); + subdev_spec_pair->db_name = NULL; + } + if(subdev_spec_pair->sd_name){ + free(subdev_spec_pair->sd_name); + subdev_spec_pair->sd_name = NULL; + } + ) +} + +uhd_error uhd_subdev_spec_pairs_equal( + const uhd_subdev_spec_pair_t* first, + const uhd_subdev_spec_pair_t* second, + bool *result_out +){ + UHD_SAFE_C( + *result_out = (uhd_subdev_spec_pair_c_to_cpp(first) == + uhd_subdev_spec_pair_c_to_cpp(second)); + ) +} + +uhd_error uhd_subdev_spec_make( + uhd_subdev_spec_handle* h, + const char* markup +){ + UHD_SAFE_C( + (*h) = new uhd_subdev_spec_t; + std::string markup_cpp(markup); + if(!markup_cpp.empty()){ + (*h)->subdev_spec_cpp = uhd::usrp::subdev_spec_t(markup_cpp); + } + ) +} + +uhd_error uhd_subdev_spec_free( + uhd_subdev_spec_handle* h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_subdev_spec_size( + uhd_subdev_spec_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->subdev_spec_cpp.size(); + ) +} + +uhd_error uhd_subdev_spec_push_back( + uhd_subdev_spec_handle h, + const char* markup +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->subdev_spec_cpp.push_back(uhd::usrp::subdev_spec_pair_t(markup)); + ) +} + +uhd_error uhd_subdev_spec_at( + uhd_subdev_spec_handle h, + size_t num, + uhd_subdev_spec_pair_t *subdev_spec_pair_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd_subdev_spec_pair_cpp_to_c( + h->subdev_spec_cpp.at(num), + subdev_spec_pair_out + ); + ) +} + +uhd_error uhd_subdev_spec_to_pp_string( + uhd_subdev_spec_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->subdev_spec_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_subdev_spec_to_string( + uhd_subdev_spec_handle h, + char* string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string string_cpp = h->subdev_spec_cpp.to_string(); + memset(string_out, '\0', strbuffer_len); + strncpy(string_out, string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_subdev_spec_last_error( + uhd_subdev_spec_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +uhd::usrp::subdev_spec_pair_t uhd_subdev_spec_pair_c_to_cpp( + const uhd_subdev_spec_pair_t *subdev_spec_pair_c +){ + return uhd::usrp::subdev_spec_pair_t(subdev_spec_pair_c->db_name, + subdev_spec_pair_c->sd_name); +} + +void uhd_subdev_spec_pair_cpp_to_c( + const uhd::usrp::subdev_spec_pair_t &subdev_spec_pair_cpp, + uhd_subdev_spec_pair_t *subdev_spec_pair_c +){ + subdev_spec_pair_c->db_name = strdup(subdev_spec_pair_cpp.db_name.c_str()); + subdev_spec_pair_c->sd_name = strdup(subdev_spec_pair_cpp.sd_name.c_str()); +} diff --git a/host/lib/usrp/usrp2/n200_image_loader.cpp b/host/lib/usrp/usrp2/n200_image_loader.cpp index ce956c22c..29bec8b4a 100644 --- a/host/lib/usrp/usrp2/n200_image_loader.cpp +++ b/host/lib/usrp/usrp2/n200_image_loader.cpp @@ -210,36 +210,62 @@ static uhd::device_addr_t n200_find(const image_loader::image_loader_args_t &ima image_loader_args.args.has_key("name"); uhd::device_addrs_t found = usrp2_find(image_loader_args.args); - if(found.size() > 0){ - uhd::device_addr_t ret = found[0]; - - /* - * Make sure the device found is an N-Series and not a USRP2. A USRP2 - * will not respond to this query. If the user supplied specific - * arguments that led to a USRP2, throw an error. - */ - udp_simple::sptr rev_xport = udp_simple::make_connected( - ret["addr"], - BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) - ); + if(found.size() > 0){ + uhd::device_addrs_t n200_found; + udp_simple::sptr rev_xport; n200_fw_update_data_t pkt_out; boost::uint8_t data_in[udp_simple::mtu]; const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(data_in); + size_t len = 0; - size_t len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); - if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ - boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); - ret["hw_rev"] = n200_filename_map.get(rev, "n2xx"); - return ret; + /* + * Filter out any USRP2 devices by sending a query over the + * UDP update port. Only N-Series devices will respond to + * this query. If the user supplied specific arguments that + * led to a USRP2, throw an error. + */ + BOOST_FOREACH(const uhd::device_addr_t &dev, found){ + rev_xport = udp_simple::make_connected( + dev.get("addr"), + BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) + ); + + len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); + if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ + boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); + std::string hw_rev = n200_filename_map.get(rev, "n2xx"); + + n200_found.push_back(dev); + n200_found[n200_found.size()-1]["hw_rev"] = hw_rev; + } + else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ + throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") + % ntohl(pkt_in->id))); + } + else if(user_specified){ + // At this point, we haven't received any response, so assume it's a USRP2 + print_usrp2_error(image_loader_args); + } } - else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ - throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") - % ntohl(pkt_in->id))); + + // At this point, we should have a single N-Series device + if(n200_found.size() == 1){ + return n200_found[0]; } - else if(user_specified){ - // At this point, we haven't received any response, so assume it's a USRP2 - print_usrp2_error(image_loader_args); + else if(n200_found.size() > 1){ + std::string err_msg = "Could not resolve given args to a single N-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, n200_found){ + err_msg += str(boost::format("* %s (addr=%s)\n") + % dev.get("hw_rev") + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); } } @@ -259,7 +285,7 @@ static void n200_validate_firmware_image(n200_session_t &session){ session.max_size = N200_FW_MAX_SIZE_BYTES; if(session.size > session.max_size){ - throw uhd::runtime_error(str(boost::format("The specified FPGA image is too large: %d vs. %d") + throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") % session.size % session.max_size)); } @@ -559,11 +585,15 @@ static std::string nice_name(const std::string &fw_rev){ } static bool n200_image_loader(const image_loader::image_loader_args_t &image_loader_args){ + if(!image_loader_args.load_firmware and !image_loader_args.load_fpga){ + return false; + } + // See if any N2x0 with the given args is found // This will throw if specific args lead to a USRP2 n200_session_t session; session.dev_addr = n200_find(image_loader_args); - if(session.dev_addr.size() == 0 or (!image_loader_args.load_firmware and !image_loader_args.load_fpga)){ + if(session.dev_addr.size() == 0){ return false; } diff --git a/host/lib/usrp/usrp_c.cpp b/host/lib/usrp/usrp_c.cpp new file mode 100644 index 000000000..829014829 --- /dev/null +++ b/host/lib/usrp/usrp_c.cpp @@ -0,0 +1,1523 @@ +/* + * Copyright 2015 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/>. + */ + +/* C-Interface for multi_usrp */ + +#include <uhd/utils/static.hpp> +#include <uhd/usrp/multi_usrp.hpp> + +#include <uhd/error.h> +#include <uhd/usrp/usrp.h> + +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> + +#include <string.h> +#include <map> + +/**************************************************************************** + * Helpers + ***************************************************************************/ +uhd::stream_args_t stream_args_c_to_cpp(const uhd_stream_args_t *stream_args_c) +{ + std::string otw_format(stream_args_c->otw_format); + std::string cpu_format(stream_args_c->cpu_format); + std::string args(stream_args_c->args); + std::vector<size_t> channels(stream_args_c->channel_list, stream_args_c->channel_list + stream_args_c->n_channels); + + uhd::stream_args_t stream_args_cpp(cpu_format, otw_format); + stream_args_cpp.args = args; + stream_args_cpp.channels = channels; + + return stream_args_cpp; +} + +uhd::stream_cmd_t stream_cmd_c_to_cpp(const uhd_stream_cmd_t *stream_cmd_c) +{ + uhd::stream_cmd_t stream_cmd_cpp(uhd::stream_cmd_t::stream_mode_t(stream_cmd_c->stream_mode)); + stream_cmd_cpp.num_samps = stream_cmd_c->num_samps; + stream_cmd_cpp.stream_now = stream_cmd_c->stream_now; + stream_cmd_cpp.time_spec = uhd::time_spec_t(stream_cmd_c->time_spec_full_secs, stream_cmd_c->time_spec_frac_secs); + return stream_cmd_cpp; +} + +/**************************************************************************** + * Registry / Pointer Management + ***************************************************************************/ +/* Public structs */ +struct uhd_usrp { + size_t usrp_index; + std::string last_error; +}; + +struct uhd_tx_streamer { + size_t usrp_index; + size_t streamer_index; + std::string last_error; +}; + +struct uhd_rx_streamer { + size_t usrp_index; + size_t streamer_index; + std::string last_error; +}; + +/* Not public: We use this for our internal registry */ +struct usrp_ptr { + uhd::usrp::multi_usrp::sptr ptr; + std::vector< uhd::rx_streamer::sptr > rx_streamers; + std::vector< uhd::tx_streamer::sptr > tx_streamers; + static size_t usrp_counter; +}; +size_t usrp_ptr::usrp_counter = 0; +typedef struct usrp_ptr usrp_ptr; +/* Prefer map, because the list can be discontiguous */ +typedef std::map<size_t, usrp_ptr> usrp_ptrs; + +UHD_SINGLETON_FCN(usrp_ptrs, get_usrp_ptrs); +/* Shortcut for accessing the underlying USRP sptr from a uhd_usrp_handle* */ +#define USRP(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].ptr) +#define RX_STREAMER(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].rx_streamers[h_ptr->streamer_index]) +#define TX_STREAMER(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].tx_streamers[h_ptr->streamer_index]) + +/**************************************************************************** + * RX Streamer + ***************************************************************************/ +static boost::mutex _rx_streamer_make_mutex; +uhd_error uhd_rx_streamer_make(uhd_rx_streamer_handle* h){ + UHD_SAFE_C( + boost::mutex::scoped_lock(_rx_streamer_make_mutex); + (*h) = new uhd_rx_streamer; + ) +} + +static boost::mutex _rx_streamer_free_mutex; +uhd_error uhd_rx_streamer_free(uhd_rx_streamer_handle* h){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_rx_streamer_free_mutex); + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_rx_streamer_num_channels(uhd_rx_streamer_handle h, + size_t *num_channels_out){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = RX_STREAMER(h)->get_num_channels(); + ) +} + +uhd_error uhd_rx_streamer_max_num_samps(uhd_rx_streamer_handle h, + size_t *max_num_samps_out){ + UHD_SAFE_C_SAVE_ERROR(h, + *max_num_samps_out = RX_STREAMER(h)->get_max_num_samps(); + ) +} + +uhd_error uhd_rx_streamer_recv( + uhd_rx_streamer_handle h, + void **buffs, + size_t samps_per_buff, + uhd_rx_metadata_handle md, + double timeout, + bool one_packet, + size_t *items_recvd +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::rx_streamer::buffs_type buffs_cpp(buffs, RX_STREAMER(h)->get_num_channels()); + *items_recvd = RX_STREAMER(h)->recv(buffs_cpp, samps_per_buff, md->rx_metadata_cpp, timeout, one_packet); + ) +} + +uhd_error uhd_rx_streamer_issue_stream_cmd( + uhd_rx_streamer_handle h, + const uhd_stream_cmd_t *stream_cmd +){ + UHD_SAFE_C_SAVE_ERROR(h, + RX_STREAMER(h)->issue_stream_cmd(stream_cmd_c_to_cpp(stream_cmd)); + ) +} + +uhd_error uhd_rx_streamer_last_error( + uhd_rx_streamer_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/**************************************************************************** + * TX Streamer + ***************************************************************************/ +static boost::mutex _tx_streamer_make_mutex; +uhd_error uhd_tx_streamer_make( + uhd_tx_streamer_handle* h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_tx_streamer_make_mutex); + (*h) = new uhd_tx_streamer; + ) +} + +static boost::mutex _tx_streamer_free_mutex; +uhd_error uhd_tx_streamer_free( + uhd_tx_streamer_handle* h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_tx_streamer_free_mutex); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_tx_streamer_num_channels( + uhd_tx_streamer_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = TX_STREAMER(h)->get_num_channels(); + ) +} + +uhd_error uhd_tx_streamer_max_num_samps( + uhd_tx_streamer_handle h, + size_t *max_num_samps_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *max_num_samps_out = TX_STREAMER(h)->get_max_num_samps(); + ) +} + +uhd_error uhd_tx_streamer_send( + uhd_tx_streamer_handle h, + const void **buffs, + const size_t samps_per_buff, + const uhd_tx_metadata_handle md, + const double timeout, + size_t *items_sent +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tx_streamer::buffs_type buffs_cpp(buffs, TX_STREAMER(h)->get_num_channels()); + *items_sent = TX_STREAMER(h)->send( + buffs_cpp, + samps_per_buff, + md->tx_metadata_cpp, + timeout + ); + ) +} + +uhd_error uhd_tx_streamer_recv_async_msg( + uhd_tx_streamer_handle h, + uhd_async_metadata_handle md, + const double timeout, + bool *valid +){ + UHD_SAFE_C_SAVE_ERROR(h, + *valid = TX_STREAMER(h)->recv_async_msg(md->async_metadata_cpp, timeout); + ) +} + +uhd_error uhd_tx_streamer_last_error( + uhd_tx_streamer_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/**************************************************************************** + * Generate / Destroy API calls + ***************************************************************************/ +static boost::mutex _usrp_find_mutex; +uhd_error uhd_usrp_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +){ + UHD_SAFE_C_SAVE_ERROR(h, + boost::mutex::scoped_lock _lock(_usrp_find_mutex); + + h->device_addrs_cpp = uhd::device::find(std::string(args), uhd::device::USRP); + *num_found = h->device_addrs_cpp.size(); + ) +} + +static boost::mutex _usrp_make_mutex; +uhd_error uhd_usrp_make( + uhd_usrp_handle *h, + const char *args +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_make_mutex); + + size_t usrp_count = usrp_ptr::usrp_counter; + usrp_ptr::usrp_counter++; + + // Initialize USRP + uhd::device_addr_t device_addr(args); + usrp_ptr P; + P.ptr = uhd::usrp::multi_usrp::make(device_addr); + + // Dump into registry + get_usrp_ptrs()[usrp_count] = P; + + // Update handle + (*h) = new uhd_usrp; + (*h)->usrp_index = usrp_count; + ) +} + +static boost::mutex _usrp_free_mutex; +uhd_error uhd_usrp_free( + uhd_usrp_handle *h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_free_mutex); + + if(!get_usrp_ptrs().count((*h)->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + get_usrp_ptrs().erase((*h)->usrp_index); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_usrp_last_error( + uhd_usrp_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +static boost::mutex _usrp_get_rx_stream_mutex; +uhd_error uhd_usrp_get_rx_stream( + uhd_usrp_handle h_u, + uhd_stream_args_t *stream_args, + uhd_rx_streamer_handle h_s +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_get_rx_stream_mutex); + + if(!get_usrp_ptrs().count(h_u->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + usrp_ptr &usrp = get_usrp_ptrs()[h_u->usrp_index]; + usrp.rx_streamers.push_back( + usrp.ptr->get_rx_stream(stream_args_c_to_cpp(stream_args)) + ); + h_s->usrp_index = h_u->usrp_index; + h_s->streamer_index = usrp.rx_streamers.size() - 1; + ) +} + +static boost::mutex _usrp_get_tx_stream_mutex; +uhd_error uhd_usrp_get_tx_stream( + uhd_usrp_handle h_u, + uhd_stream_args_t *stream_args, + uhd_tx_streamer_handle h_s +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_get_tx_stream_mutex); + + if(!get_usrp_ptrs().count(h_u->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + usrp_ptr &usrp = get_usrp_ptrs()[h_u->usrp_index]; + usrp.tx_streamers.push_back( + usrp.ptr->get_tx_stream(stream_args_c_to_cpp(stream_args)) + ); + h_s->usrp_index = h_u->usrp_index; + h_s->streamer_index = usrp.tx_streamers.size() - 1; + ) +} + +/**************************************************************************** + * multi_usrp API calls + ***************************************************************************/ + +#define COPY_INFO_FIELD(out, dict, field) \ + out->field = strdup(dict.get(BOOST_STRINGIZE(field)).c_str()) + +uhd_error uhd_usrp_get_rx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_rx_info_t *info_out +) { + UHD_SAFE_C_SAVE_ERROR(h, + uhd::dict<std::string, std::string> rx_info = USRP(h)->get_usrp_rx_info(chan); + + COPY_INFO_FIELD(info_out, rx_info, mboard_id); + COPY_INFO_FIELD(info_out, rx_info, mboard_serial); + COPY_INFO_FIELD(info_out, rx_info, rx_id); + COPY_INFO_FIELD(info_out, rx_info, rx_subdev_name); + COPY_INFO_FIELD(info_out, rx_info, rx_subdev_spec); + COPY_INFO_FIELD(info_out, rx_info, rx_serial); + COPY_INFO_FIELD(info_out, rx_info, rx_antenna); + ) +} + +uhd_error uhd_usrp_get_tx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_tx_info_t *info_out +) { + UHD_SAFE_C_SAVE_ERROR(h, + uhd::dict<std::string, std::string> tx_info = USRP(h)->get_usrp_tx_info(chan); + + COPY_INFO_FIELD(info_out, tx_info, mboard_id); + COPY_INFO_FIELD(info_out, tx_info, mboard_serial); + COPY_INFO_FIELD(info_out, tx_info, tx_id); + COPY_INFO_FIELD(info_out, tx_info, tx_subdev_name); + COPY_INFO_FIELD(info_out, tx_info, tx_subdev_spec); + COPY_INFO_FIELD(info_out, tx_info, tx_serial); + COPY_INFO_FIELD(info_out, tx_info, tx_antenna); + ) +} + +/**************************************************************************** + * Motherboard methods + ***************************************************************************/ +uhd_error uhd_usrp_set_master_clock_rate( + uhd_usrp_handle h, + double rate, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_master_clock_rate(rate, mboard); + ) +} + +uhd_error uhd_usrp_get_master_clock_rate( + uhd_usrp_handle h, + size_t mboard, + double *clock_rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *clock_rate_out = USRP(h)->get_master_clock_rate(mboard); + ) +} + +uhd_error uhd_usrp_get_pp_string( + uhd_usrp_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(pp_string_out, USRP(h)->get_pp_string().c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_mboard_name( + uhd_usrp_handle h, + size_t mboard, + char* mboard_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(mboard_name_out, USRP(h)->get_mboard_name(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_time_now( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = USRP(h)->get_time_now(mboard); + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_usrp_get_time_last_pps( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = USRP(h)->get_time_last_pps(mboard); + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_usrp_set_time_now( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_now(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_set_time_next_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_next_pps(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_set_time_unknown_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_unknown_pps(time_spec_cpp); + ) +} + +uhd_error uhd_usrp_get_time_synchronized( + uhd_usrp_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = USRP(h)->get_time_synchronized(); + return UHD_ERROR_NONE; + ) +} + +uhd_error uhd_usrp_set_command_time( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_command_time(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_clear_command_time( + uhd_usrp_handle h, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->clear_command_time(mboard); + ) +} + +uhd_error uhd_usrp_issue_stream_cmd( + uhd_usrp_handle h, + uhd_stream_cmd_t *stream_cmd, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->issue_stream_cmd(stream_cmd_c_to_cpp(stream_cmd), chan); + ) +} + +uhd_error uhd_usrp_set_time_source( + uhd_usrp_handle h, + const char* time_source, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_time_source(std::string(time_source), mboard); + ) +} + +uhd_error uhd_usrp_get_time_source( + uhd_usrp_handle h, + size_t mboard, + char* time_source_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(time_source_out, USRP(h)->get_time_source(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_time_sources( + uhd_usrp_handle h, + size_t mboard, + char* time_sources_out, + size_t strbuffer_len, + size_t *num_time_sources_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> time_sources = USRP(h)->get_time_sources(mboard); + *num_time_sources_out = time_sources.size(); + + std::string time_sources_str = ""; + BOOST_FOREACH(const std::string &time_source, time_sources){ + time_sources_str += time_source; + time_sources_str += ','; + } + if(time_sources.size() > 0){ + time_sources_str.resize(time_sources_str.size()-1); + } + + memset(time_sources_out, '\0', strbuffer_len); + strncpy(time_sources_out, time_sources_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_clock_source( + uhd_usrp_handle h, + const char* clock_source, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_clock_source(std::string(clock_source), mboard); + ) +} + +uhd_error uhd_usrp_get_clock_source( + uhd_usrp_handle h, + size_t mboard, + char* clock_source_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(clock_source_out, USRP(h)->get_clock_source(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_clock_sources( + uhd_usrp_handle h, + size_t mboard, + char* clock_sources_out, + size_t strbuffer_len, + size_t *num_clock_sources_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> clock_sources = USRP(h)->get_clock_sources(mboard); + *num_clock_sources_out = clock_sources.size(); + + std::string clock_sources_str = ""; + BOOST_FOREACH(const std::string &clock_source, clock_sources){ + clock_sources_str += clock_source; + clock_sources_str += ','; + } + if(clock_sources.size() > 0){ + clock_sources_str.resize(clock_sources_str.size()-1); + } + + memset(clock_sources_out, '\0', strbuffer_len); + strncpy(clock_sources_out, clock_sources_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_clock_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_clock_source_out(enb, mboard); + ) +} + +uhd_error uhd_usrp_get_num_mboards( + uhd_usrp_handle h, + size_t *num_mboards_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_mboards_out = USRP(h)->get_num_mboards(); + ) +} + +uhd_error uhd_usrp_get_mboard_sensor( + uhd_usrp_handle h, + const char* name, + size_t mboard, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_mboard_sensor(name, mboard)); + ) +} + +uhd_error uhd_usrp_get_mboard_sensor_names( + uhd_usrp_handle h, + size_t mboard, + char* mboard_sensor_names_out, + size_t strbuffer_len, + size_t *num_mboard_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> mboard_sensor_names = USRP(h)->get_mboard_sensor_names(mboard); + *num_mboard_sensors_out = mboard_sensor_names.size(); + + std::string mboard_sensor_names_str = ""; + BOOST_FOREACH(const std::string &mboard_sensor_name, mboard_sensor_names){ + mboard_sensor_names_str += mboard_sensor_name; + mboard_sensor_names_str += ','; + } + if(mboard_sensor_names.size() > 0){ + mboard_sensor_names_str.resize(mboard_sensor_names_str.size()-1); + } + + memset(mboard_sensor_names_out, '\0', strbuffer_len); + strncpy(mboard_sensor_names_out, mboard_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_user_register( + uhd_usrp_handle h, + uint8_t addr, + uint32_t data, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_user_register(addr, data, mboard); + ) +} + +/**************************************************************************** + * EEPROM access methods + ***************************************************************************/ + +uhd_error uhd_usrp_get_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/eeprom") + % mboard); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + mb_eeprom->mboard_eeprom_cpp = ptree->access<uhd::usrp::mboard_eeprom_t>(eeprom_path).get(); + ) +} + +uhd_error uhd_usrp_set_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/eeprom") + % mboard); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + ptree->access<uhd::usrp::mboard_eeprom_t>(eeprom_path).set(mb_eeprom->mboard_eeprom_cpp); + ) +} + +uhd_error uhd_usrp_get_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/dboards/%s/%s_eeprom") + % mboard % slot % unit); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + db_eeprom->dboard_eeprom_cpp = ptree->access<uhd::usrp::dboard_eeprom_t>(eeprom_path).get(); + ) +} + +uhd_error uhd_usrp_set_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/dboards/%s/%s_eeprom") + % mboard % slot % unit); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + ptree->access<uhd::usrp::dboard_eeprom_t>(eeprom_path).set(db_eeprom->dboard_eeprom_cpp); + ) +} + +/**************************************************************************** + * RX methods + ***************************************************************************/ + +uhd_error uhd_usrp_set_rx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_subdev_spec(subdev_spec->subdev_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_get_rx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + subdev_spec_out->subdev_spec_cpp = USRP(h)->get_rx_subdev_spec(mboard); + ) +} + +uhd_error uhd_usrp_get_rx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = USRP(h)->get_rx_num_channels(); + ) +} + +uhd_error uhd_usrp_get_rx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* rx_subdev_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string rx_subdev_name = USRP(h)->get_rx_subdev_name(chan); + strncpy(rx_subdev_name_out, rx_subdev_name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_rate(rate, chan); + ) +} + +uhd_error uhd_usrp_get_rx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *rate_out = USRP(h)->get_rx_rate(chan); + ) +} + +uhd_error uhd_usrp_get_rx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + rates_out->meta_range_cpp = USRP(h)->get_rx_rates(chan); + ) +} + +uhd_error uhd_usrp_set_rx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tune_request_t tune_request_cpp = uhd_tune_request_c_to_cpp(tune_request); + uhd::tune_result_t tune_result_cpp = USRP(h)->set_rx_freq(tune_request_cpp, chan); + uhd_tune_result_cpp_to_c(tune_result_cpp, tune_result); + ) +} + +uhd_error uhd_usrp_get_rx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *freq_out = USRP(h)->get_rx_freq(chan); + ) +} + +uhd_error uhd_usrp_get_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_rx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_get_fe_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_fe_rx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_set_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + USRP(h)->set_rx_gain(gain, chan); + } + else{ + USRP(h)->set_rx_gain(gain, name, chan); + } + ) +} + +uhd_error uhd_usrp_set_normalized_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_normalized_rx_gain(gain, chan); + ) +} + +uhd_error uhd_usrp_set_rx_agc( + uhd_usrp_handle h, + bool enable, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_agc(enable, chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + *gain_out = USRP(h)->get_rx_gain(chan); + } + else{ + *gain_out = USRP(h)->get_rx_gain(name, chan); + } + ) +} + +uhd_error uhd_usrp_get_normalized_rx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *gain_out = USRP(h)->get_normalized_rx_gain(chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + gain_range_out->meta_range_cpp = USRP(h)->get_rx_gain_range(name, chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_rx_gain_names_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_gain_names = USRP(h)->get_rx_gain_names(chan); + *num_rx_gain_names_out = rx_gain_names.size(); + + std::string rx_gain_names_str = ""; + BOOST_FOREACH(const std::string &gain_name, rx_gain_names){ + rx_gain_names_str += gain_name; + rx_gain_names_str += ','; + } + if(rx_gain_names.size() > 0){ + rx_gain_names_str.resize(rx_gain_names_str.size()-1); + } + + memset(gain_names_out, '\0', strbuffer_len); + strncpy(gain_names_out, rx_gain_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_antenna(std::string(ant), chan); + ) +} + +uhd_error uhd_usrp_get_rx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string rx_antenna = USRP(h)->get_rx_antenna(chan); + strncpy(ant_out, rx_antenna.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_rx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_rx_antennas_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_antennas = USRP(h)->get_rx_antennas(chan); + *num_rx_antennas_out = rx_antennas.size(); + + std::string rx_antennas_str = ""; + BOOST_FOREACH(const std::string &rx_antenna, rx_antennas){ + rx_antennas_str += rx_antenna; + rx_antennas_str += ','; + } + if(rx_antennas.size() > 0){ + rx_antennas_str.resize(rx_antennas_str.size()-1); + } + + memset(antennas_out, '\0', strbuffer_len); + strncpy(antennas_out, rx_antennas_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_bandwidth(bandwidth, chan); + ) +} + +uhd_error uhd_usrp_get_rx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *bandwidth_out = USRP(h)->get_rx_bandwidth(chan); + ) +} + +uhd_error uhd_usrp_get_rx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + bandwidth_range_out->meta_range_cpp = USRP(h)->get_rx_bandwidth_range(chan); + ) +} + +uhd_error uhd_usrp_get_rx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_rx_sensor(name, chan)); + ) +} + +uhd_error uhd_usrp_get_rx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_rx_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_sensor_names = USRP(h)->get_rx_sensor_names(chan); + *num_rx_sensors_out = rx_sensor_names.size(); + + std::string rx_sensor_names_str = ""; + BOOST_FOREACH(const std::string &rx_sensor_name, rx_sensor_names){ + rx_sensor_names_str += rx_sensor_name; + rx_sensor_names_str += ','; + } + if(rx_sensor_names.size() > 0){ + rx_sensor_names_str.resize(rx_sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, rx_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_dc_offset(enb, chan); + ) +} + +uhd_error uhd_usrp_set_rx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_iq_balance(enb, chan); + ) +} + +/**************************************************************************** + * TX methods + ***************************************************************************/ + +uhd_error uhd_usrp_set_tx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_subdev_spec(subdev_spec->subdev_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_get_tx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + subdev_spec_out->subdev_spec_cpp = USRP(h)->get_tx_subdev_spec(mboard); + ) +} + + +uhd_error uhd_usrp_get_tx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = USRP(h)->get_tx_num_channels(); + ) +} + +uhd_error uhd_usrp_get_tx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* tx_subdev_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string tx_subdev_name = USRP(h)->get_tx_subdev_name(chan); + strncpy(tx_subdev_name_out, tx_subdev_name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_rate(rate, chan); + ) +} + +uhd_error uhd_usrp_get_tx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *rate_out = USRP(h)->get_tx_rate(chan); + ) +} + +uhd_error uhd_usrp_get_tx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + rates_out->meta_range_cpp = USRP(h)->get_tx_rates(chan); + ) +} + +uhd_error uhd_usrp_set_tx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tune_request_t tune_request_cpp = uhd_tune_request_c_to_cpp(tune_request); + uhd::tune_result_t tune_result_cpp = USRP(h)->set_tx_freq(tune_request_cpp, chan); + uhd_tune_result_cpp_to_c(tune_result_cpp, tune_result); + ) +} + +uhd_error uhd_usrp_get_tx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *freq_out = USRP(h)->get_tx_freq(chan); + ) +} + +uhd_error uhd_usrp_get_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_tx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_get_fe_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_fe_tx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_set_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + USRP(h)->set_tx_gain(gain, chan); + } + else{ + USRP(h)->set_tx_gain(gain, name, chan); + } + ) +} + +uhd_error uhd_usrp_set_normalized_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_normalized_tx_gain(gain, chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + *gain_out = USRP(h)->get_tx_gain(chan); + } + else{ + *gain_out = USRP(h)->get_tx_gain(name, chan); + } + ) +} + +uhd_error uhd_usrp_get_normalized_tx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *gain_out = USRP(h)->get_normalized_tx_gain(chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + gain_range_out->meta_range_cpp = USRP(h)->get_tx_gain_range(name, chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_tx_gain_names_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_gain_names = USRP(h)->get_tx_gain_names(chan); + *num_tx_gain_names_out = tx_gain_names.size(); + + std::string tx_gain_names_str = ""; + BOOST_FOREACH(const std::string &tx_gain_name, tx_gain_names){ + tx_gain_names_str += tx_gain_name; + tx_gain_names_str += ','; + } + if(tx_gain_names.size() > 0){ + tx_gain_names_str.resize(tx_gain_names_str.size()-1); + } + + memset(gain_names_out, '\0', strbuffer_len); + strncpy(gain_names_out, tx_gain_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_antenna(std::string(ant), chan); + ) +} + +uhd_error uhd_usrp_get_tx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string tx_antenna = USRP(h)->get_tx_antenna(chan); + strncpy(ant_out, tx_antenna.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_tx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_tx_antennas_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_antennas = USRP(h)->get_tx_antennas(chan); + *num_tx_antennas_out = tx_antennas.size(); + + std::string tx_antennas_str = ""; + BOOST_FOREACH(const std::string &tx_antenna, tx_antennas){ + tx_antennas_str += tx_antenna; + tx_antennas_str += ','; + } + if(tx_antennas.size() > 0){ + tx_antennas_str.resize(tx_antennas_str.size()-1); + } + + memset(antennas_out, '\0', strbuffer_len); + strncpy(antennas_out, tx_antennas_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_bandwidth(bandwidth, chan); + ) +} + +uhd_error uhd_usrp_get_tx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *bandwidth_out = USRP(h)->get_tx_bandwidth(chan); + ) +} + +uhd_error uhd_usrp_get_tx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + bandwidth_range_out->meta_range_cpp = USRP(h)->get_tx_bandwidth_range(chan); + ) +} + +uhd_error uhd_usrp_get_tx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_tx_sensor(name, chan)); + ) +} + +uhd_error uhd_usrp_get_tx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_tx_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_sensor_names = USRP(h)->get_tx_sensor_names(chan); + *num_tx_sensors_out = tx_sensor_names.size(); + + std::string tx_sensor_names_str = ""; + BOOST_FOREACH(const std::string &tx_sensor_name, tx_sensor_names){ + tx_sensor_names_str += tx_sensor_name; + tx_sensor_names_str += ','; + } + if(tx_sensor_names.size() > 0){ + tx_sensor_names_str.resize(tx_sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, tx_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_dc_offset(enb, chan); + ) +} + +uhd_error uhd_usrp_set_tx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_iq_balance(enb, chan); + ) +} + +/**************************************************************************** + * GPIO methods + ***************************************************************************/ + +uhd_error uhd_usrp_get_gpio_banks( + uhd_usrp_handle h, + size_t chan, + char* gpio_banks_out, + size_t strbuffer_len, + size_t *num_gpio_banks_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> gpio_banks = USRP(h)->get_gpio_banks(chan); + *num_gpio_banks_out = gpio_banks.size(); + + std::string gpio_banks_str = ""; + BOOST_FOREACH(const std::string &gpio_bank, gpio_banks){ + gpio_banks_str += gpio_bank; + gpio_banks_str += ','; + } + if(gpio_banks.size() > 0){ + gpio_banks_str.resize(gpio_banks_str.size()-1); + } + + memset(gpio_banks_out, '\0', strbuffer_len); + strncpy(gpio_banks_out, gpio_banks_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + uint32_t value, + uint32_t mask, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_gpio_attr(std::string(bank), std::string(attr), + value, mask, mboard); + ) +} + +uhd_error uhd_usrp_get_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + size_t mboard, + uint32_t *attr_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *attr_out = USRP(h)->get_gpio_attr(std::string(bank), std::string(attr), mboard); + ) +} diff --git a/host/lib/usrp/x300/x300_adc_dac_utils.cpp b/host/lib/usrp/x300/x300_adc_dac_utils.cpp index b1483b3a5..e08825749 100644 --- a/host/lib/usrp/x300/x300_adc_dac_utils.cpp +++ b/host/lib/usrp/x300/x300_adc_dac_utils.cpp @@ -41,7 +41,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) //Get a rough estimate of the cumulative command latency boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time(); for (size_t i = 0; i < radios.size(); i++) { - radios[i]->ctrl->peek64(RB64_TIME_NOW); //Discard value. We are just timing the call + radios[i]->ctrl->peek64(uhd::usrp::radio::RB64_TIME_NOW); //Discard value. We are just timing the call } boost::posix_time::time_duration t_elapsed = boost::posix_time::microsec_clock::local_time() - t_start; @@ -56,7 +56,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) //Send the sync command for (size_t i = 0; i < radios.size(); i++) { radios[i]->ctrl->set_time(sync_time); - radios[i]->ctrl->poke32(TOREG(SR_DACSYNC), 0x1); //Arm FRAMEP/N sync pulse + radios[i]->ctrl->poke32(uhd::usrp::radio::sr_addr(uhd::usrp::radio::DACSYNC), 0x1); //Arm FRAMEP/N sync pulse radios[i]->ctrl->set_time(uhd::time_spec_t(0.0)); //Clear command time } @@ -73,7 +73,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) static void check_adc(uhd::wb_iface::sptr iface, const boost::uint32_t val, const boost::uint32_t i) { - boost::uint32_t adc_rb = iface->peek32(RB32_RX); + boost::uint32_t adc_rb = iface->peek32(uhd::usrp::radio::RB32_RX); adc_rb ^= 0xfffc0000; //adapt for I inversion in FPGA if (val != adc_rb) { throw uhd::runtime_error( diff --git a/host/lib/usrp/x300/x300_image_loader.cpp b/host/lib/usrp/x300/x300_image_loader.cpp index 321309868..9ec8a2e13 100644 --- a/host/lib/usrp/x300/x300_image_loader.cpp +++ b/host/lib/usrp/x300/x300_image_loader.cpp @@ -158,17 +158,31 @@ static void x300_validate_image(x300_session_t &session){ static void x300_setup_session(x300_session_t &session, const device_addr_t &args, const std::string &filepath){ - device_addr_t find_args; - find_args["type"] = "x300"; - if(args.has_key("name")) find_args["name"] = args["name"]; - if(args.has_key("serial")) find_args["serial"] = args["serial"]; - if(args.has_key("ip-addr")) find_args["addr"] = args["ip-addr"]; - else if(args.has_key("resource")) find_args["resource"] = args["resource"]; - device_addrs_t devs = x300_find(args); - session.found = (devs.size() > 0); - if(!session.found) return; + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single X-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string identifier = dev.has_key("addr") ? "addr" + : "resource"; + + err_msg += str(boost::format(" * %s (%s=%s)\n") + % dev.get("product", "X3XX") + % identifier + % dev.get(identifier)); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + session.found = true; session.dev_addr = devs[0]; session.ethernet = session.dev_addr.has_key("addr"); if(session.ethernet){ diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 437fec82d..229bf7b23 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -29,6 +29,7 @@ #include <uhd/transport/if_addrs.hpp> #include <boost/foreach.hpp> #include <boost/bind.hpp> +#include <boost/make_shared.hpp> #include <boost/functional/hash.hpp> #include <boost/assign/list_of.hpp> #include <fstream> @@ -410,7 +411,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //Tell the quirks object which FIFOs carry TX stream data const boost::uint32_t tx_data_fifos[2] = {X300_RADIO_DEST_PREFIX_TX, X300_RADIO_DEST_PREFIX_TX + 3}; - mb.rio_fpga_interface->get_kernel_proxy()->get_rio_quirks().register_tx_streams(tx_data_fifos); + mb.rio_fpga_interface->get_kernel_proxy()->get_rio_quirks().register_tx_streams(tx_data_fifos, 2); _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_PCIE); } @@ -748,7 +749,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// // front panel gpio //////////////////////////////////////////////////////////////////// - mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); + mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second) @@ -943,30 +944,30 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con //////////////////////////////////////////////////////////////// // Setup peripherals //////////////////////////////////////////////////////////////// - perif.spi = spi_core_3000::make(perif.ctrl, TOREG(SR_SPI), RB32_SPI); + perif.spi = spi_core_3000::make(perif.ctrl, radio::sr_addr(radio::SPI), radio::RB32_SPI); perif.adc = x300_adc_ctrl::make(perif.spi, DB_ADC_SEN); perif.dac = x300_dac_ctrl::make(perif.spi, DB_DAC_SEN, mb.clock->get_master_clock_rate()); - perif.leds = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_LEDS)); - perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); + perif.leds = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::LEDS)); + perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); - perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); + perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::TX_FRONT)); perif.tx_fe->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.tx_fe->set_iq_balance(tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); - perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP)); + perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); + perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); - perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever //////////////////////////////////////////////////////////////////// // create time control objects //////////////////////////////////////////////////////////////////// time_core_3000::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_now = RB64_TIME_NOW; - time64_rb_bases.rb_pps = RB64_TIME_PPS; - perif.time64 = time_core_3000::make(perif.ctrl, TOREG(SR_TIME), time64_rb_bases); + time64_rb_bases.rb_now = radio::RB64_TIME_NOW; + time64_rb_bases.rb_pps = radio::RB64_TIME_PPS; + perif.time64 = time_core_3000::make(perif.ctrl, radio::sr_addr(radio::TIME), time64_rb_bases); //Capture delays are calibrated every time. The status is only printed is the user //asks to run the xfer self cal using "self_cal_adc_delay" @@ -1030,7 +1031,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con //create a new dboard interface x300_dboard_iface_config_t db_config; - db_config.gpio = gpio_core_200::make(perif.ctrl, TOREG(SR_GPIO), RB32_GPIO); + db_config.gpio = gpio_core_200::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO); db_config.spi = perif.spi; db_config.rx_spi_slaveno = DB_RX_SEN; db_config.tx_spi_slaveno = DB_TX_SEN; @@ -1343,8 +1344,8 @@ void x300_impl::register_loopback_self_test(wb_iface::sptr iface) for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); - iface->poke32(TOREG(SR_TEST), boost::uint32_t(hash)); - test_fail = iface->peek32(RB32_TEST) != boost::uint32_t(hash); + iface->poke32(radio::sr_addr(radio::TEST), boost::uint32_t(hash)); + test_fail = iface->peek32(radio::RB32_TEST) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 350845f28..eba30abb5 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -18,40 +18,47 @@ #ifndef INCLUDED_X300_REGS_HPP #define INCLUDED_X300_REGS_HPP +#include <uhd/config.hpp> #include <stdint.h> -#include <boost/cstdint.hpp> #include <uhd/utils/soft_register.hpp> -#define TOREG(x) ((x)*4) +namespace uhd { namespace usrp { namespace radio { + +static UHD_INLINE uint32_t sr_addr(const uint32_t offset) +{ + return offset * 4; +} + +static const uint32_t DACSYNC = 5; +static const uint32_t LOOPBACK = 6; +static const uint32_t TEST = 7; +static const uint32_t SPI = 8; +static const uint32_t GPIO = 16; +static const uint32_t MISC_OUTS = 24; +static const uint32_t READBACK = 32; +static const uint32_t TX_CTRL = 64; +static const uint32_t RX_CTRL = 96; +static const uint32_t TIME = 128; +static const uint32_t RX_DSP = 144; +static const uint32_t TX_DSP = 184; +static const uint32_t LEDS = 195; +static const uint32_t FP_GPIO = 200; +static const uint32_t RX_FRONT = 208; +static const uint32_t TX_FRONT = 216; + +static const uint32_t RB32_GPIO = 0; +static const uint32_t RB32_SPI = 4; +static const uint32_t RB64_TIME_NOW = 8; +static const uint32_t RB64_TIME_PPS = 16; +static const uint32_t RB32_TEST = 24; +static const uint32_t RB32_RX = 28; +static const uint32_t RB32_FP_GPIO = 32; +static const uint32_t RB32_MISC_INS = 36; + +}}} // namespace #define localparam static const int -localparam SR_DACSYNC = 5; -localparam SR_LOOPBACK = 6; -localparam SR_TEST = 7; -localparam SR_SPI = 8; -localparam SR_GPIO = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK = 32; -localparam SR_TX_CTRL = 64; -localparam SR_RX_CTRL = 96; -localparam SR_TIME = 128; -localparam SR_RX_DSP = 144; -localparam SR_TX_DSP = 184; -localparam SR_LEDS = 195; -localparam SR_FP_GPIO = 200; -localparam SR_RX_FRONT = 208; -localparam SR_TX_FRONT = 216; - -localparam RB32_GPIO = 0; -localparam RB32_SPI = 4; -localparam RB64_TIME_NOW = 8; -localparam RB64_TIME_PPS = 16; -localparam RB32_TEST = 24; -localparam RB32_RX = 28; -localparam RB32_FP_GPIO = 32; -localparam RB32_MISC_INS = 36; - localparam BL_ADDRESS = 0; localparam BL_DATA = 1; @@ -247,7 +254,7 @@ namespace uhd { namespace usrp { namespace x300 { UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL, /*width*/ 5, /*shift*/ 4); //[8:4] UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER_ENABLED, /*width*/ 1, /*shift*/ 9); //[9] - misc_outs_reg_t(): uhd::soft_reg32_wo_t(TOREG(SR_MISC_OUTS)) { + misc_outs_reg_t(): uhd::soft_reg32_wo_t(uhd::usrp::radio::sr_addr(uhd::usrp::radio::MISC_OUTS)) { //Initial values set(DAC_ENABLED, 0); set(DAC_RESET_N, 0); @@ -269,7 +276,7 @@ namespace uhd { namespace usrp { namespace x300 { UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_Q_ERROR, /*width*/ 1, /*shift*/ 6); //[6] UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_I_ERROR, /*width*/ 1, /*shift*/ 7); //[7] - misc_ins_reg_t(): uhd::soft_reg32_ro_t(RB32_MISC_INS) { } + misc_ins_reg_t(): uhd::soft_reg32_ro_t(uhd::usrp::radio::RB32_MISC_INS) { } } misc_ins_reg; radio_regmap_t(int radio_num) : soft_regmap_t("radio" + boost::lexical_cast<std::string>(radio_num) + "_regmap") { diff --git a/host/lib/usrp_clock/CMakeLists.txt b/host/lib/usrp_clock/CMakeLists.txt index 8a58aa9ac..ba0f5fe0a 100644 --- a/host/lib/usrp_clock/CMakeLists.txt +++ b/host/lib/usrp_clock/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2011-2014 Ettus Research LLC +# Copyright 2011-2015 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 @@ -23,4 +23,10 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp_clock.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_clock_c.cpp + ) +ENDIF(ENABLE_C_API) + INCLUDE_SUBDIRECTORY(octoclock) diff --git a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp index c88177f0f..e8c50e029 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -51,7 +51,7 @@ using namespace uhd::transport; * OctoClock burn session */ typedef struct { - bool valid; + bool found; uhd::device_addr_t dev_addr; std::string given_filepath; std::string actual_filepath; // If using a .hex, this is the converted .bin @@ -113,18 +113,43 @@ static void octoclock_validate_firmware_image(octoclock_session_t &session){ : (session.size / OCTOCLOCK_BLOCK_SIZE); octoclock_calculate_crc(session); - session.valid = true; } static void octoclock_setup_session(octoclock_session_t &session, + const uhd::device_addr_t &args, const std::string &filepath){ + // See if we can find an OctoClock with the given args + device_addrs_t devs = octoclock_find(args); + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single OctoClock device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string name = (dev["type"] == "octoclock") ? str(boost::format("OctoClock r%d") + % dev.get("revision","4")) + : "OctoClock Bootloader"; + err_msg += str(boost::format(" * %s (addr=%s)\n") + % name + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + + session.dev_addr = devs[0]; + // If no filepath is given, use the default if(filepath == ""){ - session.given_filepath = find_image_path(str(boost::format("octoclock_r%d_fw.hex") - % boost::lexical_cast<std::string>( - session.dev_addr.get("revision","4") - ))); + session.given_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") + % session.dev_addr.get("revision","4") + )); } else session.given_filepath = filepath; @@ -287,7 +312,7 @@ static void octoclock_verify(octoclock_session_t &session){ } static void octoclock_finalize(octoclock_session_t &session){ - + octoclock_packet_t pkt_out; pkt_out.sequence = htonx<boost::uint32_t>(std::rand()); const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); @@ -305,15 +330,12 @@ static void octoclock_finalize(octoclock_session_t &session){ } bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loader_args){ - // See if we can find an OctoClock with the given args - device_addrs_t devs = octoclock_find(image_loader_args.args); - if(devs.size() == 0 or !image_loader_args.load_firmware) return false; - octoclock_session_t session; - session.dev_addr = devs[0]; octoclock_setup_session(session, + image_loader_args.args, image_loader_args.firmware_path ); + if(!session.found or !image_loader_args.load_firmware) return false; std::cout << boost::format("Unit: OctoClock (%s)") % session.dev_addr["addr"] @@ -329,7 +351,7 @@ bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loade UHD_STATIC_BLOCK(register_octoclock_image_loader){ std::string recovery_instructions = "Aborting. Your OctoClock firmware is now corrupt. The bootloader\n" - "is functional, but the device will not have functional clock distribution." + "is functional, but the device will not have functional clock distribution.\n" "Run this utility again to restore functionality or refer to:\n\n" "http://files.ettus.com/manual/page_octoclock.html\n\n" "for alternative setups."; diff --git a/host/lib/usrp_clock/usrp_clock_c.cpp b/host/lib/usrp_clock/usrp_clock_c.cpp new file mode 100644 index 000000000..dc5913534 --- /dev/null +++ b/host/lib/usrp_clock/usrp_clock_c.cpp @@ -0,0 +1,189 @@ +/* + * Copyright 2015 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/>. + */ + +/* C-Interface for multi_usrp_clock */ + +#include <uhd/utils/static.hpp> +#include <uhd/usrp_clock/multi_usrp_clock.hpp> + +#include <uhd/usrp_clock/usrp_clock.h> + +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> + +#include <string.h> +#include <map> + +/**************************************************************************** + * Registry / Pointer Management + ***************************************************************************/ +/* Public structs */ +struct uhd_usrp_clock { + size_t usrp_clock_index; + std::string last_error; +}; + +/* Not public: We use this for our internal registry */ +struct usrp_clock_ptr { + uhd::usrp_clock::multi_usrp_clock::sptr ptr; + static size_t usrp_clock_counter; +}; +size_t usrp_clock_ptr::usrp_clock_counter = 0; +typedef struct usrp_clock_ptr usrp_clock_ptr; +/* Prefer map, because the list can be discontiguous */ +typedef std::map<size_t, usrp_clock_ptr> usrp_clock_ptrs; + +UHD_SINGLETON_FCN(usrp_clock_ptrs, get_usrp_clock_ptrs); +/* Shortcut for accessing the underlying USRP clock sptr from a uhd_usrp_clock_handle* */ +#define USRP_CLOCK(h_ptr) (get_usrp_clock_ptrs()[h_ptr->usrp_clock_index].ptr) + +/**************************************************************************** + * Generate / Destroy API calls + ***************************************************************************/ +static boost::mutex _usrp_clock_find_mutex; +uhd_error uhd_usrp_clock_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +){ + UHD_SAFE_C_SAVE_ERROR(h, + boost::mutex::scoped_lock lock(_usrp_clock_find_mutex); + + h->device_addrs_cpp = uhd::device::find(std::string(args), uhd::device::CLOCK); + *num_found = h->device_addrs_cpp.size(); + ) +} + +static boost::mutex _usrp_clock_make_mutex; +uhd_error uhd_usrp_clock_make( + uhd_usrp_clock_handle *h, + const char *args +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_clock_make_mutex); + + size_t usrp_clock_count = usrp_clock_ptr::usrp_clock_counter; + usrp_clock_ptr::usrp_clock_counter++; + + // Initialize USRP Clock + uhd::device_addr_t device_addr(args); + usrp_clock_ptr P; + P.ptr = uhd::usrp_clock::multi_usrp_clock::make(device_addr); + + // Dump into registry + get_usrp_clock_ptrs()[usrp_clock_count] = P; + + // Update handle + (*h) = new uhd_usrp_clock; + (*h)->usrp_clock_index = usrp_clock_count; + ) +} + +static boost::mutex _usrp_clock_free_mutex; +uhd_error uhd_usrp_clock_free( + uhd_usrp_clock_handle *h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_clock_free_mutex); + + if(!get_usrp_clock_ptrs().count((*h)->usrp_clock_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + get_usrp_clock_ptrs().erase((*h)->usrp_clock_index); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_usrp_clock_last_error( + uhd_usrp_clock_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_clock_get_pp_string( + uhd_usrp_clock_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, USRP_CLOCK(h)->get_pp_string().c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_clock_get_num_boards( + uhd_usrp_clock_handle h, + size_t *num_boards_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_boards_out = USRP_CLOCK(h)->get_num_boards(); + ) +} + +uhd_error uhd_usrp_clock_get_time( + uhd_usrp_clock_handle h, + size_t board, + uint32_t *clock_time_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *clock_time_out = USRP_CLOCK(h)->get_time(board); + ) +} + +uhd_error uhd_usrp_clock_get_sensor( + uhd_usrp_clock_handle h, + const char* name, + size_t board, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP_CLOCK(h)->get_sensor(name, board)); + ) +} + +uhd_error uhd_usrp_clock_get_sensor_names( + uhd_usrp_clock_handle h, + size_t board, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> sensor_names = USRP_CLOCK(h)->get_sensor_names(board); + *num_sensors_out = sensor_names.size(); + + std::string sensor_names_str = ""; + BOOST_FOREACH(const std::string &sensor_name, sensor_names){ + sensor_names_str += sensor_name; + sensor_names_str += ','; + } + if(sensor_names.size() > 0){ + sensor_names_str.resize(sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, sensor_names_str.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index 369920ac1..c5c975dfa 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -141,3 +141,9 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/tasks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp ) + +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority_c.cpp + ) +ENDIF(ENABLE_C_API) diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp index af25d088a..98023c5aa 100644 --- a/host/lib/utils/thread_priority.cpp +++ b/host/lib/utils/thread_priority.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,2015 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 diff --git a/host/lib/utils/thread_priority_c.cpp b/host/lib/utils/thread_priority_c.cpp new file mode 100644 index 000000000..fe019e51d --- /dev/null +++ b/host/lib/utils/thread_priority_c.cpp @@ -0,0 +1,33 @@ +// +// Copyright 2015 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/>. +// + +#include <uhd/error.h> +#include <uhd/utils/thread_priority.h> +#include <uhd/utils/thread_priority.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <iostream> + +uhd_error uhd_set_thread_priority( + float priority, + bool realtime +){ + UHD_SAFE_C( + uhd::set_thread_priority(priority, realtime); + ) +} |