aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorAshish Chaudhari <ashish@ettus.com>2015-08-10 23:14:20 -0700
committerAshish Chaudhari <ashish@ettus.com>2015-08-10 23:14:20 -0700
commitb5c81677078f56b3e671ebeaca1e3b803c2f4ef9 (patch)
treea1b17b4be203331de7e146e94051f26be5a20102 /host/lib
parent16e149fe6fcc1bc18adea3eeeefad2c7ee93b2e0 (diff)
parent28327c8e8a810b19da126116d0dc4c26b643baed (diff)
downloaduhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.tar.gz
uhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.tar.bz2
uhd-b5c81677078f56b3e671ebeaca1e3b803c2f4ef9.zip
Merge branch 'master' into ashish/register_api
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/CMakeLists.txt6
-rw-r--r--host/lib/convert/convert_common.hpp1
-rw-r--r--host/lib/convert/convert_impl.cpp1
-rw-r--r--host/lib/convert/gen_convert_general.py88
-rw-r--r--host/lib/error_c.cpp40
-rw-r--r--host/lib/exception.cpp5
-rw-r--r--host/lib/transport/libusb1_base.cpp28
-rw-r--r--host/lib/transport/libusb1_base.hpp27
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp75
-rw-r--r--host/lib/transport/udp_zero_copy.cpp9
-rw-r--r--host/lib/types/CMakeLists.txt11
-rw-r--r--host/lib/types/device_addrs_c.cpp78
-rw-r--r--host/lib/types/metadata_c.cpp315
-rw-r--r--host/lib/types/ranges_c.cpp162
-rw-r--r--host/lib/types/sensors_c.cpp228
-rw-r--r--host/lib/types/tune_c.cpp76
-rw-r--r--host/lib/types/usrp_info_c.cpp44
-rw-r--r--host/lib/usrp/CMakeLists.txt11
-rw-r--r--host/lib/usrp/b200/b200_image_loader.cpp33
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp39
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp12
-rw-r--r--host/lib/usrp/common/ad936x_manager.cpp2
-rw-r--r--host/lib/usrp/dboard_eeprom_c.cpp109
-rw-r--r--host/lib/usrp/e300/CMakeLists.txt4
-rw-r--r--host/lib/usrp/e300/e300_common.cpp16
-rw-r--r--host/lib/usrp/e300/e300_impl.cpp39
-rw-r--r--host/lib/usrp/e300/e300_regs.hpp62
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.cpp4
-rw-r--r--host/lib/usrp/mboard_eeprom_c.cpp72
-rw-r--r--host/lib/usrp/subdev_spec_c.cpp149
-rw-r--r--host/lib/usrp/usrp2/n200_image_loader.cpp80
-rw-r--r--host/lib/usrp/usrp_c.cpp1523
-rw-r--r--host/lib/usrp/x300/x300_adc_dac_utils.cpp6
-rw-r--r--host/lib/usrp/x300/x300_image_loader.cpp32
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp33
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp67
-rw-r--r--host/lib/usrp_clock/CMakeLists.txt8
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp48
-rw-r--r--host/lib/usrp_clock/usrp_clock_c.cpp189
-rw-r--r--host/lib/utils/CMakeLists.txt6
-rw-r--r--host/lib/utils/thread_priority.cpp2
-rw-r--r--host/lib/utils/thread_priority_c.cpp33
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);
+ )
+}