From bd293b70f4128210b79823e1ce8597ba08d09df6 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 15 Jan 2015 16:23:12 +0100 Subject: convert: Added converters for raw strings - u8: Converts arbitrary-length strings from and to item32 - item32->item32 memcpy non-conversion --- host/lib/convert/convert_common.hpp | 1 + host/lib/convert/convert_impl.cpp | 1 + host/lib/convert/gen_convert_general.py | 88 +++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 14 deletions(-) (limited to 'host/lib') 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 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(inputs[0]); + item32_t *output = reinterpret_cast(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(inputs[0]); item32_t *output = reinterpret_cast(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(inputs[0]); item32_t *output = reinterpret_cast(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(inputs[0]); + boost::uint32_t *output = reinterpret_cast(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(&input[n_words]); + u8_t *last_output_word = reinterpret_cast(&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(inputs[0]); + boost::uint32_t *output = reinterpret_cast(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(&last_input_word); + u8_t *last_output_word = reinterpret_cast(&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'), -- cgit v1.2.3 From 0c7d748bbf6c282d3f1c759201e40f35f26133ca Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 14 Apr 2015 15:12:04 -0500 Subject: x300: nirio: Fix compiler warnings The old code used a non standard (though very common) way to determine the size of an array. In order to avoid warnings, pass another parameter to indicate the size. Signed-off-by: Moritz Fischer --- host/include/uhd/transport/nirio/nirio_quirks.h | 4 ++-- host/lib/usrp/x300/x300_impl.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/transport/nirio/nirio_quirks.h b/host/include/uhd/transport/nirio/nirio_quirks.h index 8e58f80f1..45ef40394 100644 --- a/host/include/uhd/transport/nirio/nirio_quirks.h +++ b/host/include/uhd/transport/nirio/nirio_quirks.h @@ -35,8 +35,8 @@ public: nirio_quirks() : _tx_stream_count(0) { } - UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[]) { - for (size_t i = 0; i < sizeof(tx_stream_indices)/sizeof(*tx_stream_indices); i++) { + UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[], size_t size) { + for (size_t i = 0; i < size; i++) { _tx_stream_fifo_indices.insert(tx_stream_indices[i]); } } diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index f0332691d..c9cc0cabc 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -409,7 +409,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(mb_path / "link_max_rate").set(X300_MAX_RATE_PCIE); } -- cgit v1.2.3 From e956fc124029394f8d4a9157e1feeb0b76f0e8ee Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Fri, 31 Jul 2015 16:39:28 -0700 Subject: b200: fixed initial loading --- host/lib/usrp/b200/b200_impl.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index b45529c1a..3445f125b 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -125,8 +125,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 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 +156,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);} -- cgit v1.2.3 From e1672fa7eedb00a977c39b7e80bb18521493b524 Mon Sep 17 00:00:00 2001 From: Balint Seeber Date: Mon, 27 Jul 2015 14:15:29 -0700 Subject: uhd: Added usb_error exception type --- host/include/uhd/exception.hpp | 8 ++++++++ host/lib/exception.cpp | 5 +++++ 2 files changed, 13 insertions(+) (limited to 'host/lib') diff --git a/host/include/uhd/exception.hpp b/host/include/uhd/exception.hpp index 69e902fd5..a21106166 100644 --- a/host/include/uhd/exception.hpp +++ b/host/include/uhd/exception.hpp @@ -98,6 +98,14 @@ namespace uhd{ virtual void dynamic_throw(void) const; }; + struct UHD_API usb_error : runtime_error{ + int _code; + usb_error(int code, const std::string &what); + virtual unsigned code(void) const { return _code; }; + virtual usb_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; + }; + struct UHD_API not_implemented_error : runtime_error{ not_implemented_error(const std::string &what); virtual unsigned code(void) const; 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;} -- cgit v1.2.3 From 4ed2b26d512ed8c8e78fbbfcf25a3560fd8c7102 Mon Sep 17 00:00:00 2001 From: Balint Seeber Date: Mon, 27 Jul 2015 15:16:49 -0700 Subject: b200: Change init sequence to catch bad USB states - Fixes USB hang issues on OS X - Uses usb_errors --- host/lib/transport/libusb1_base.cpp | 15 ++++++++++++++ host/lib/transport/libusb1_base.hpp | 4 ++++ host/lib/transport/libusb1_zero_copy.cpp | 4 ++-- host/lib/usrp/b200/b200_impl.cpp | 34 +++++++++++++++++++++++++------- host/lib/usrp/b200/b200_impl.hpp | 12 ++++++++++- 5 files changed, 59 insertions(+), 10 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 0baf8dc76..9635d34b0 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -251,6 +251,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..2e16dc176 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -135,6 +135,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..465adc95e 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -148,14 +148,14 @@ public: UHD_INLINE void submit(void) { - _lut->length = (_is_recv)? _frame_size : size(); //always set length + _lut->length = (_is_recv)? _frame_size : size(); //always set length #ifdef UHD_TXRX_DEBUG_PRINTS result.start_time = boost::get_system_time().time_of_day().total_microseconds(); result.buff_num = num(); result.is_recv = _is_recv; #endif const int ret = libusb_submit_transfer(_lut); - if (ret != 0) throw uhd::runtime_error(str(boost::format( + if (ret != 0) throw uhd::usb_error(ret, str(boost::format( "usb %s submit failed: %s") % _name % libusb_error_name(ret))); } diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 3445f125b..f5129bc24 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -37,6 +37,8 @@ #include #include +#include "../../transport/libusb1_base.hpp" + using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; @@ -194,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(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) @@ -205,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 { @@ -262,7 +281,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : std::vector 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; @@ -360,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 @@ -442,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 -- cgit v1.2.3 From bb62ab84fdad6f7cf18ea55d395dfbd7f11ed79d Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Wed, 5 Aug 2015 08:46:28 -0700 Subject: image_loader: force user to specify device * On utility level, force user to use --args=type=foo * In each loader, throw an error if args are ambiguous --- host/include/uhd/image_loader.hpp | 3 +- host/lib/usrp/b200/b200_image_loader.cpp | 33 +++++++-- host/lib/usrp/usrp2/n200_image_loader.cpp | 80 +++++++++++++++------- host/lib/usrp/x300/x300_image_loader.cpp | 32 ++++++--- .../octoclock/octoclock_image_loader.cpp | 48 +++++++++---- host/utils/uhd_image_loader.cpp | 5 ++ 6 files changed, 148 insertions(+), 53 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/image_loader.hpp b/host/include/uhd/image_loader.hpp index 8124e7dea..5963c862f 100644 --- a/host/include/uhd/image_loader.hpp +++ b/host/include/uhd/image_loader.hpp @@ -46,8 +46,9 @@ public: * * This function must return true upon the end of a successful image load * or false if no applicable device was found. It may only throw a runtime - * error under one of two conditions: + * error under one of three conditions: * + * * The function finds multiple devices that fit the user's arguments. * * The function has already engaged with a specific device and * something goes wrong. * * The user gives arguments that unambiguously lead to a specific 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 dev_handles = get_b200_device_handles(image_loader_args.args); + std::vector 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/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(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/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_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( - 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(std::rand()); const octoclock_packet_t* pkt_in = reinterpret_cast(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/utils/uhd_image_loader.cpp b/host/utils/uhd_image_loader.cpp index 39efc8f1e..5ea789ee2 100644 --- a/host/utils/uhd_image_loader.cpp +++ b/host/utils/uhd_image_loader.cpp @@ -91,6 +91,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ image_loader_args.firmware_path = vm["fw-path"].as(); image_loader_args.fpga_path = vm["fpga-path"].as(); + // Force user to specify a device + if(not image_loader_args.args.has_key("type")){ + throw uhd::runtime_error("You must specify a device type."); + } + // Clean up paths, if given if(image_loader_args.firmware_path != ""){ #ifndef UHD_PLATFORM_WIN32 -- cgit v1.2.3 From b08352f267730ea417ec345cd90833a6746a1114 Mon Sep 17 00:00:00 2001 From: michael-west Date: Wed, 29 Jul 2015 16:55:38 -0700 Subject: Fix for BUG 869: UHD: Unhandled exceptions during destruction of multi_usrp object cause application to terminate - Prevented libusb_zero_copy_single from submitting transfers after libusb reports an error - Made error messages in libusb_zero_copy and udp_zero_copy more descriptive --- host/lib/transport/libusb1_base.cpp | 13 ++++++- host/lib/transport/libusb1_zero_copy.cpp | 60 +++++++++++++++++++++----------- host/lib/transport/udp_zero_copy.cpp | 9 ++++- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 9635d34b0..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; + } } }; diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 465adc95e..fe0eb9bfd 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -148,15 +148,16 @@ public: UHD_INLINE void submit(void) { - _lut->length = (_is_recv)? _frame_size : size(); //always set length + _lut->length = (_is_recv)? _frame_size : size(); //always set length #ifdef UHD_TXRX_DEBUG_PRINTS result.start_time = boost::get_system_time().time_of_day().total_microseconds(); result.buff_num = num(); result.is_recv = _is_recv; #endif const int ret = libusb_submit_transfer(_lut); - if (ret != 0) throw uhd::usb_error(ret, 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 @@ -164,8 +165,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(this), _lut->buffer, (_is_recv)? result.actual_length : _frame_size); } @@ -219,7 +221,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(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 +307,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 == 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(timeout); - lock.lock(); + queue_lock.lock(); if (buff) _enqueued.pop_front(); this->submit_what_we_can(); @@ -333,28 +342,39 @@ private: buffer_pool::sptr _buffer_pool; std::vector > _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 _enqueued, _released; + enum {RUNNING,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 == 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 = 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(); -- cgit v1.2.3 From 30f87afcba71a07fbd28d51318e791448c28314e Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Thu, 6 Aug 2015 10:42:23 -0700 Subject: uhd: C API wrapper * multi_usrp, multi_usrp_clock, and associated classes accessible through C * Added Doxygen documentation explaining structure and API * Simple RX and TX streaming examples * Unit tests for different parts of C interface and C++ error conversion --- host/CMakeLists.txt | 1 + host/cmake/msvc/stdbool.h | 33 + host/docs/CMakeLists.txt | 2 +- host/docs/c_api.dox | 86 ++ host/docs/coding.dox | 5 + host/examples/CMakeLists.txt | 47 +- host/examples/getopt/CMakeLists.txt | 25 + host/examples/getopt/getopt.c | 1056 +++++++++++++++++++ host/examples/getopt/getopt.h | 180 ++++ host/examples/getopt/getopt1.c | 188 ++++ host/examples/rx_samples_c.c | 291 ++++++ host/examples/tx_samples_c.c | 241 +++++ host/include/CMakeLists.txt | 7 + host/include/uhd.h | 40 + host/include/uhd/CMakeLists.txt | 11 +- host/include/uhd/config.h | 82 ++ host/include/uhd/error.h | 136 +++ host/include/uhd/types/CMakeLists.txt | 13 + host/include/uhd/types/metadata.h | 364 +++++++ host/include/uhd/types/ranges.h | 154 +++ host/include/uhd/types/sensors.h | 231 +++++ host/include/uhd/types/stream_cmd.hpp | 34 +- host/include/uhd/types/tune_request.h | 61 ++ host/include/uhd/types/tune_result.h | 60 ++ host/include/uhd/types/usrp_info.h | 94 ++ host/include/uhd/usrp/CMakeLists.txt | 14 +- host/include/uhd/usrp/dboard_eeprom.h | 110 ++ host/include/uhd/usrp/mboard_eeprom.h | 87 ++ host/include/uhd/usrp/subdev_spec.h | 137 +++ host/include/uhd/usrp/usrp.h | 1242 +++++++++++++++++++++++ host/include/uhd/usrp_clock/CMakeLists.txt | 6 + host/include/uhd/usrp_clock/usrp_clock.h | 117 +++ host/include/uhd/utils/CMakeLists.txt | 8 + host/include/uhd/utils/thread_priority.h | 53 + host/lib/CMakeLists.txt | 6 + host/lib/error_c.cpp | 40 + host/lib/types/CMakeLists.txt | 10 + host/lib/types/metadata_c.cpp | 315 ++++++ host/lib/types/ranges_c.cpp | 162 +++ host/lib/types/sensors_c.cpp | 228 +++++ host/lib/types/tune_c.cpp | 76 ++ host/lib/types/usrp_info_c.cpp | 44 + host/lib/usrp/CMakeLists.txt | 11 +- host/lib/usrp/dboard_eeprom_c.cpp | 109 ++ host/lib/usrp/mboard_eeprom_c.cpp | 72 ++ host/lib/usrp/subdev_spec_c.cpp | 149 +++ host/lib/usrp/usrp_c.cpp | 1509 ++++++++++++++++++++++++++++ host/lib/usrp_clock/CMakeLists.txt | 8 +- host/lib/usrp_clock/usrp_clock_c.cpp | 175 ++++ host/lib/utils/CMakeLists.txt | 6 + host/lib/utils/thread_priority.cpp | 2 +- host/lib/utils/thread_priority_c.cpp | 33 + host/tests/CMakeLists.txt | 10 + host/tests/eeprom_c_test.c | 155 +++ host/tests/error_c_test.cpp | 142 +++ host/tests/ranges_c_test.c | 236 +++++ host/tests/sensors_c_test.c | 411 ++++++++ host/tests/subdev_spec_c_test.c | 130 +++ 58 files changed, 9230 insertions(+), 25 deletions(-) create mode 100644 host/cmake/msvc/stdbool.h create mode 100644 host/docs/c_api.dox create mode 100644 host/examples/getopt/CMakeLists.txt create mode 100644 host/examples/getopt/getopt.c create mode 100644 host/examples/getopt/getopt.h create mode 100644 host/examples/getopt/getopt1.c create mode 100644 host/examples/rx_samples_c.c create mode 100644 host/examples/tx_samples_c.c create mode 100644 host/include/uhd.h create mode 100644 host/include/uhd/config.h create mode 100644 host/include/uhd/error.h create mode 100644 host/include/uhd/types/metadata.h create mode 100644 host/include/uhd/types/ranges.h create mode 100644 host/include/uhd/types/sensors.h create mode 100644 host/include/uhd/types/tune_request.h create mode 100644 host/include/uhd/types/tune_result.h create mode 100644 host/include/uhd/types/usrp_info.h create mode 100644 host/include/uhd/usrp/dboard_eeprom.h create mode 100644 host/include/uhd/usrp/mboard_eeprom.h create mode 100644 host/include/uhd/usrp/subdev_spec.h create mode 100644 host/include/uhd/usrp/usrp.h create mode 100644 host/include/uhd/usrp_clock/usrp_clock.h create mode 100644 host/include/uhd/utils/thread_priority.h create mode 100644 host/lib/error_c.cpp create mode 100644 host/lib/types/metadata_c.cpp create mode 100644 host/lib/types/ranges_c.cpp create mode 100644 host/lib/types/sensors_c.cpp create mode 100644 host/lib/types/tune_c.cpp create mode 100644 host/lib/types/usrp_info_c.cpp create mode 100644 host/lib/usrp/dboard_eeprom_c.cpp create mode 100644 host/lib/usrp/mboard_eeprom_c.cpp create mode 100644 host/lib/usrp/subdev_spec_c.cpp create mode 100644 host/lib/usrp/usrp_c.cpp create mode 100644 host/lib/usrp_clock/usrp_clock_c.cpp create mode 100644 host/lib/utils/thread_priority_c.cpp create mode 100644 host/tests/eeprom_c_test.c create mode 100644 host/tests/error_c_test.cpp create mode 100644 host/tests/ranges_c_test.c create mode 100644 host/tests/sensors_c_test.c create mode 100644 host/tests/subdev_spec_c_test.c (limited to 'host/lib') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 2f59bada4..89447c12c 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -277,6 +277,7 @@ SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.009.git-269-gb6ad4c05.zip") # Register top level components ######################################################################## LIBUHD_REGISTER_COMPONENT("LibUHD" ENABLE_LIBUHD ON "Boost_FOUND;HAVE_PYTHON_PLAT_MIN_VERSION;HAVE_PYTHON_MODULE_MAKO" OFF) +LIBUHD_REGISTER_COMPONENT("LibUHD - C API" ENABLE_C_API ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Examples" ENABLE_EXAMPLES ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Utils" ENABLE_UTILS ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Tests" ENABLE_TESTS ON "ENABLE_LIBUHD" OFF) diff --git a/host/cmake/msvc/stdbool.h b/host/cmake/msvc/stdbool.h new file mode 100644 index 000000000..3a91eea37 --- /dev/null +++ b/host/cmake/msvc/stdbool.h @@ -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 . +// + +#ifndef INCLUDED_MSC_STDBOOL_H +#define INCLUDED_MSC_STDBOOL_H + +#ifndef _MSC_VER +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif + +#ifndef __cplusplus + +#define bool int +#define true 1 +#define false 0 + +#endif + +#endif /* INCLUDED_MSC_STDBOOL_H */ diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 79488e373..3ad2ef37c 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -74,7 +74,7 @@ ENDIF(LIBUHDDEV_PKG) IF(ENABLE_DOXYGEN) SET(ENABLE_MANUAL_OR_DOXYGEN true) #make doxygen directory depend on the header files - FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp) + FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.h*) SET(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files}) IF(ENABLE_DOXYGEN_FULL) SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib") diff --git a/host/docs/c_api.dox b/host/docs/c_api.dox new file mode 100644 index 000000000..5b5790f21 --- /dev/null +++ b/host/docs/c_api.dox @@ -0,0 +1,86 @@ +/*! \page page_c_api UHD - C API + +\tableofcontents + +\section c_api_intro Introduction + +Alongside its C++ API, UHD provides a C API wrapper for the uhd::usrp::multi_usrp and +uhd::usrp_clock::multi_usrp_clock classes, as well as their associated classes and +structs. Other important UHD functions are also included in this API. To use this +API, simply: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +#include +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +...and all UHD C-level structs and functions will be available to you. The sections below +give more detail on the key features of the C API. + +\subsection c_api_handles C-Level Handles + +Most of the UHD classes that can be accessed on the C level are done so through handles, +which internally store the C++ representation and allow access to internal values +through helper functions. + +All handles have associated *_make() and *_free() functions. After creating a handle, it must +be passed through its make() function before it can be used in your program. Before the program +terminates, you must pass the handle into its free() function, or your program will have a memory +leak. The example below shows the proper usage of an RX metadata handle over the course of its +lifetime, from instantiation to destruction. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +uhd_rx_metadata_handle md; +uhd_rx_metadata_make(&md); + +// Streaming here puts useful information into metadata +time_t full_secs; +double frac_secs; +uhd_rx_metadata_time_spec(md, &full_secs, &frac_secs); + +uhd_rx_metadata_free(&md); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Again, make sure to pass your handle into a make() function before using it, or you will +run into undefined behavior. Also be careful not to use the handle after passing it into +a free() function, or your program will segfault. + +\subsection c_api_errorcode Error Codes + +As C cannot handle C++ runtime exceptions, UHD's C wrapper functions catch all exceptions +and translate them into error codes, which are returned by each function. Any output variables +are passed in as pointers into the function, which will set them internally. + +Each uhd::runtime_error has a corresponding ::uhd_error value. Separate error codes indicate +that a boost::exception or std::exception has been thrown, and any other exceptions are +indicated by a catch-all ::UHD_ERROR_UNKNOWN code. + +All UHD C-level handles store the string representation of the last C++ exception thrown internally. +These handles have corresponding *_get_last_error() functions that will place the error string into a +supplied string buffer. + +For example, if a USRP device's handle throws an exception internally, the following code can access +its error info: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +char err_msg[256]; +uhd_usrp_handle usrp; +double gain; +// USRP configuration done here +uhd_error error_code = uhd_usrp_get_rx_gain(usrp, 0, "", &gain); +if(error_code){ + uhd_usrp_get_last_error(usrp, err_msg, 256); + fprintf(stderr, "Error code %d: %s\n", error_code, err_msg); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All error codes can be found in . + +\subsection c_api_examples Example Code + +UHD provides two examples that demonstrate the typical use case of the C API: RX and TX streaming. +The rx_samples_c example is a simplified C version of rx_samples_to_file, +and the tx_samples_c example is a simplified C version of tx_waveforms. These examples +can be easily adapted or serve as a starting point for your own UHD C applications. + +*/ +// vim:ft=doxygen: diff --git a/host/docs/coding.dox b/host/docs/coding.dox index 32dbe944a..6a15098d7 100644 --- a/host/docs/coding.dox +++ b/host/docs/coding.dox @@ -16,6 +16,11 @@ The Multi-USRP-Clock class provides a high-level interface to a single clock device or set of clock devices, from which the time can be queried. See the documentation for uhd::usrp_clock::multi_usrp_clock. +\subsection coding_api_hilevelc High-Level: The C API + +Both USRP and clock devices can be interacted with using a C API wrapper included +by default in all UHD builds. More information can be found \subpage page_c_api "here". + \subsection coding_api_lowlevel Low-Level: The device API A device is an abstraction for hardware that is connected to the host diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 92947d86c..43e0db9c0 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2014 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 @@ -61,3 +61,48 @@ IF(CURSES_FOUND) TARGET_LINK_LIBRARIES(rx_ascii_art_dft uhd ${CURSES_LIBRARIES} ${Boost_LIBRARIES}) UHD_INSTALL(TARGETS rx_ascii_art_dft RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) ENDIF(CURSES_FOUND) + +######################################################################## +# Examples using C API +######################################################################## +IF(ENABLE_C_API) + # + # Check if this particular C99 feature is available with this compiler + # + INCLUDE(CheckCSourceCompiles) + CHECK_C_SOURCE_COMPILES(" + typedef struct { + int bar; + int baz; + } foo; + + int main() + { + foo wat = { + .bar = 1, + .baz = 2 + }; + + return 0; + } + " HAVE_C99_STRUCTDECL) + + IF(HAVE_C99_STRUCTDECL) + ADD_SUBDIRECTORY(getopt) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/getopt) + + SET(C_API_EXAMPLES + rx_samples_c + tx_samples_c + ) + + FOREACH(example ${C_API_EXAMPLES}) + ADD_EXECUTABLE(${example} ${example}.c) + TARGET_LINK_LIBRARIES(${example} uhd getopt) + IF(UNIX) + TARGET_LINK_LIBRARIES(${example} m) + ENDIF(UNIX) + UHD_INSTALL(TARGETS ${example} RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) + ENDFOREACH(example ${C_API_EXAMPLES}) + ENDIF(HAVE_C99_STRUCTDECL) +ENDIF(ENABLE_C_API) diff --git a/host/examples/getopt/CMakeLists.txt b/host/examples/getopt/CMakeLists.txt new file mode 100644 index 000000000..2321a0d94 --- /dev/null +++ b/host/examples/getopt/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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 . +# + +######################################################################## +# getopt library for C examples since MSVC does not include it +######################################################################## +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIRECTORY}) +ADD_LIBRARY(getopt STATIC + ${CMAKE_CURRENT_SOURCE_DIR}/getopt.c + ${CMAKE_CURRENT_SOURCE_DIR}/getopt1.c +) diff --git a/host/examples/getopt/getopt.c b/host/examples/getopt/getopt.c new file mode 100644 index 000000000..ad9ec2f9b --- /dev/null +++ b/host/examples/getopt/getopt.c @@ -0,0 +1,1056 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(msgid) gettext (msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#include + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +#ifdef _MSC_VER +// DDK will complain if you don't use the stdlib defined getenv +#include +#else +extern char *getenv (); +#endif +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Stored original parameters. + XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (print_errors) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p != NULL && p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/host/examples/getopt/getopt.h b/host/examples/getopt/getopt.h new file mode 100644 index 000000000..a1b8dd665 --- /dev/null +++ b/host/examples/getopt/getopt.h @@ -0,0 +1,180 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include , but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include , which will pull in for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if (defined __STDC__ && __STDC__) || defined __cplusplus + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if (defined __STDC__ && __STDC__) || defined __cplusplus +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/host/examples/getopt/getopt1.c b/host/examples/getopt/getopt1.c new file mode 100644 index 000000000..22a7efbdd --- /dev/null +++ b/host/examples/getopt/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/host/examples/rx_samples_c.c b/host/examples/rx_samples_c.c new file mode 100644 index 000000000..0be0d8afe --- /dev/null +++ b/host/examples/rx_samples_c.c @@ -0,0 +1,291 @@ +/* + * 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 . + */ + +#include + +#include "getopt.h" + +#include +#include +#include + +#define EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +void print_help(void){ + fprintf(stderr, "rx_samples_c - A simple RX example using UHD's C API\n\n" + + "Options:\n" + " -a (device args)\n" + " -f (frequency in Hz)\n" + " -r (sample rate in Hz)\n" + " -g (gain)\n" + " -n (number of samples to receive)\n" + " -o (output filename, default = \"out.dat\")\n" + " -v (enable verbose prints)\n" + " -h (print this help message)\n"); +}; + +int main(int argc, char* argv[]) +{ + if(uhd_set_thread_priority(uhd_default_thread_priority, true)){ + fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n"); + } + + int option = 0; + double freq = 500e6; + double rate = 1e6; + double gain = 5.0; + char* device_args = ""; + size_t channel = 0; + char* filename = "out.dat"; + size_t n_samples = 1000000; + bool verbose = false; + int return_code = EXIT_SUCCESS; + bool custom_filename = false; + char error_string[512]; + + // Process options + while((option = getopt(argc, argv, "a:f:r:g:n:o:vh")) != -1){ + switch(option){ + case 'a': + device_args = strdup(optarg); + break; + + case 'f': + freq = atof(optarg); + break; + + case 'r': + rate = atof(optarg); + break; + + case 'g': + gain = atof(optarg); + break; + + case 'n': + n_samples = atoi(optarg); + break; + + case 'o': + filename = strdup(optarg); + custom_filename = true; + break; + + case 'v': + verbose = true; + break; + + case 'h': + print_help(); + goto free_option_strings; + + default: + print_help(); + return_code = EXIT_FAILURE; + goto free_option_strings; + } + } + + // Create USRP + uhd_usrp_handle usrp; + fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); + EXECUTE_OR_GOTO(free_usrp, + uhd_usrp_make(&usrp, device_args) + ) + + // Create RX streamer + uhd_rx_streamer_handle rx_streamer; + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_rx_streamer_make(&rx_streamer) + ) + + // Create RX metadata + uhd_rx_metadata_handle md; + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_rx_metadata_make(&md) + ) + + // Create other necessary structs + uhd_tune_request_t tune_request = { + .target_freq = freq, + .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + }; + uhd_tune_result_t tune_result; + + uhd_stream_args_t stream_args = { + .cpu_format = "fc32", + .otw_format = "sc16", + .args = "", + .channel_list = &channel, + .n_channels = 1 + }; + + uhd_stream_cmd_t stream_cmd = { + .stream_mode = UHD_STREAM_MODE_NUM_SAMPS_AND_DONE, + .num_samps = n_samples, + .stream_now = true + }; + + size_t samps_per_buff; + float *buff = NULL; + void **buffs_ptr = NULL; + FILE *fp = NULL; + size_t num_acc_samps = 0; + + // Set rate + fprintf(stderr, "Setting RX Rate: %f...\n", rate); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_rate(usrp, rate, channel) + ) + + // See what rate actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_rate(usrp, channel, &rate) + ) + fprintf(stderr, "Actual RX Rate: %f...\n", rate); + + // Set gain + fprintf(stderr, "Setting RX Gain: %f dB...\n", gain); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_gain(usrp, gain, channel, "") + ) + + // See what gain actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_gain(usrp, channel, "", &gain) + ) + fprintf(stderr, "Actual RX Gain: %f...\n", gain); + + // Set frequency + fprintf(stderr, "Setting RX frequency: %f MHz...\n", freq/1e6); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result) + ) + + // See what frequency actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_freq(usrp, channel, &freq) + ) + fprintf(stderr, "Actual RX frequency: %f MHz...\n", freq / 1e6); + + // Set up streamer + stream_args.channel_list = &channel; + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer) + ) + + // Set up buffer + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_rx_streamer_max_num_samps(rx_streamer, &samps_per_buff) + ) + fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff); + buff = malloc(samps_per_buff * 2 * sizeof(float)); + buffs_ptr = (void**)&buff; + + // Issue stream command + fprintf(stderr, "Issuing stream command.\n"); + EXECUTE_OR_GOTO(free_buffer, + uhd_rx_streamer_issue_stream_cmd(rx_streamer, &stream_cmd) + ) + + // Set up file output + fp = fopen(filename, "wb"); + + // Actual streaming + while (num_acc_samps < n_samples) { + size_t num_rx_samps = 0; + EXECUTE_OR_GOTO(close_file, + uhd_rx_streamer_recv(rx_streamer, buffs_ptr, samps_per_buff, md, 3.0, false, &num_rx_samps) + ) + + uhd_rx_metadata_error_code_t error_code; + EXECUTE_OR_GOTO(close_file, + uhd_rx_metadata_error_code(md, &error_code) + ) + if(return_code != UHD_RX_METADATA_ERROR_CODE_NONE){ + fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", return_code); + goto close_file; + } + + // Handle data + fwrite(buff, sizeof(float) * 2, num_rx_samps, fp); + if (verbose) { + time_t full_secs; + double frac_secs; + uhd_rx_metadata_time_spec(md, &full_secs, &frac_secs); + fprintf(stderr, "Received packet: %zu samples, %zu full secs, %f frac secs\n", + num_rx_samps, + full_secs, + frac_secs); + } + + num_acc_samps += num_rx_samps; + } + + // Cleanup + close_file: + fclose(fp); + + free_buffer: + if(buff){ + if(verbose){ + fprintf(stderr, "Freeing buffer.\n"); + } + free(buff); + } + buff = NULL; + buffs_ptr = NULL; + + free_rx_streamer: + if(verbose){ + fprintf(stderr, "Cleaning up RX streamer.\n"); + } + uhd_rx_streamer_free(&rx_streamer); + + free_rx_metadata: + if(verbose){ + fprintf(stderr, "Cleaning up RX metadata.\n"); + } + uhd_rx_metadata_free(&md); + + free_usrp: + if(verbose){ + fprintf(stderr, "Cleaning up USRP.\n"); + } + if(return_code != EXIT_SUCCESS){ + uhd_usrp_last_error(usrp, error_string, 512); + fprintf(stderr, "USRP reported the following error: %s\n", error_string); + } + uhd_usrp_free(&usrp); + + free_option_strings: + if(strcmp(device_args,"")){ + free(device_args); + } + if(custom_filename){ + free(filename); + } + + fprintf(stderr, (return_code ? "Failure\n" : "Success\n")); + return return_code; +} diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c new file mode 100644 index 000000000..5a4b79005 --- /dev/null +++ b/host/examples/tx_samples_c.c @@ -0,0 +1,241 @@ +/* + * 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 . + */ + +#include + +#include "getopt.h" + +#include +#include +#include +#include +#include + +#define EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +void print_help(void){ + fprintf(stderr, "tx_samples_c - A simple TX example using UHD's C API\n\n" + + "Options:\n" + " -a (device args)\n" + " -f (frequency in Hz)\n" + " -r (sample rate in Hz)\n" + " -g (gain)\n" + " -v (enable verbose prints)\n" + " -h (print this help message)\n"); +} + +bool stop_signal_called = false; + +void sigint_handler(int code){ + (void)code; + stop_signal_called = true; +} + +int main(int argc, char* argv[]){ + int option = 0; + double freq = 2e9; + double rate = 1e6; + double gain = 0; + char* device_args = ""; + size_t channel = 0; + bool verbose = false; + int return_code = EXIT_SUCCESS; + char error_string[512]; + + // Process options + while((option = getopt(argc, argv, "a:f:r:g:vh")) != -1){ + switch(option){ + case 'a': + device_args = strdup(optarg); + break; + + case 'f': + freq = atof(optarg); + break; + + case 'r': + rate = atof(optarg); + break; + + case 'g': + gain = atof(optarg); + break; + + case 'v': + verbose = true; + break; + + case 'h': + print_help(); + goto free_option_strings; + + default: + print_help(); + return_code = EXIT_FAILURE; + goto free_option_strings; + } + } + + if(uhd_set_thread_priority(uhd_default_thread_priority, true)){ + fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n"); + } + + // Create USRP + uhd_usrp_handle usrp; + fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); + EXECUTE_OR_GOTO(free_usrp, + uhd_usrp_make(&usrp, device_args) + ) + + // Create TX streamer + uhd_tx_streamer_handle tx_streamer; + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_make(&tx_streamer) + ) + + // Create TX metadata + uhd_tx_metadata_handle md; + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_tx_metadata_make(&md, false, 0.0, 0.1, true, false) + ) + + // Create other necessary structs + uhd_tune_request_t tune_request = { + .target_freq = freq, + .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO + }; + uhd_tune_result_t tune_result; + + uhd_stream_args_t stream_args = { + .cpu_format = "fc32", + .otw_format = "sc16", + .args = "", + .channel_list = &channel, + .n_channels = 1 + }; + + size_t samps_per_buff; + float* buff = NULL; + const void** buffs_ptr = NULL; + + // Set rate + fprintf(stderr, "Setting TX Rate: %f...\n", rate); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_rate(usrp, rate, channel) + ) + + // See what rate actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_rate(usrp, channel, &rate) + ) + fprintf(stderr, "Actual TX Rate: %f...\n\n", rate); + + // Set gain + fprintf(stderr, "Setting TX Gain: %f db...\n", gain); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_gain(usrp, gain, 0, "") + ) + + // See what gain actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_gain(usrp, channel, "", &gain) + ) + fprintf(stderr, "Actual TX Gain: %f...\n", gain); + + // Set frequency + fprintf(stderr, "Setting TX frequency: %f MHz...\n", freq / 1e6); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result) + ) + + // See what frequency actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_freq(usrp, channel, &freq) + ) + fprintf(stderr, "Actual TX frequency: %f MHz...\n", freq / 1e6); + + // Set up streamer + stream_args.channel_list = &channel; + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_usrp_get_tx_stream(usrp, &stream_args, tx_streamer) + ) + + // Set up buffer + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_max_num_samps(tx_streamer, &samps_per_buff) + ) + fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff); + buff = malloc(samps_per_buff * 2 * sizeof(float)); + buffs_ptr = (const void**)&buff; + size_t i = 0; + for(i = 0; i < (samps_per_buff*2); i+=2){ + buff[i] = 0.1; + buff[i+1] = 0; + } + + // Ctrl+C will exit loop + signal(SIGINT, &sigint_handler); + fprintf(stderr, "Press Ctrl+C to stop streaming...\n"); + + // Actual streaming + size_t num_samps_sent = 0; + while(!stop_signal_called){ + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_send(tx_streamer, buffs_ptr, samps_per_buff, md, 0.1, &num_samps_sent) + ) + if(verbose){ + fprintf(stderr, "Sent %zu samples\n", num_samps_sent); + } + } + + free_tx_streamer: + if(verbose){ + fprintf(stderr, "Cleaning up TX streamer.\n"); + } + uhd_tx_streamer_free(&tx_streamer); + + free_tx_metadata: + if(verbose){ + fprintf(stderr, "Cleaning up TX metadata.\n"); + } + uhd_tx_metadata_free(&md); + + free_usrp: + if(verbose){ + fprintf(stderr, "Cleaning up USRP.\n"); + } + if(return_code != EXIT_SUCCESS){ + uhd_usrp_last_error(usrp, error_string, 512); + fprintf(stderr, "USRP reported the following error: %s\n", error_string); + } + uhd_usrp_free(&usrp); + + free_option_strings: + if(strcmp(device_args,"")){ + free(device_args); + } + + fprintf(stderr, (return_code ? "Failure" : "Success")); + + return return_code; +} diff --git a/host/include/CMakeLists.txt b/host/include/CMakeLists.txt index 780213918..8b1e6bc05 100644 --- a/host/include/CMakeLists.txt +++ b/host/include/CMakeLists.txt @@ -20,4 +20,11 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_BINARY_DIR}/config.h ) +IF(ENABLE_C_API) + UHD_INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/uhd.h + DESTINATION ${INCLUDE_DIR} + COMPONENT headers + ) +ENDIF(ENABLE_C_API) + ADD_SUBDIRECTORY(uhd) diff --git a/host/include/uhd.h b/host/include/uhd.h new file mode 100644 index 000000000..0ecafa88a --- /dev/null +++ b/host/include/uhd.h @@ -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 . + */ + +#ifndef INCLUDED_UHD_H +#define INCLUDED_UHD_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#endif /* INCLUDED_UHD_H */ diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f6123aa90..083ec4951 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2011,2013-2014 Ettus Research LLC +# Copyright 2010-2011,2013-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 @@ -40,3 +40,12 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + config.h + error.h + DESTINATION ${INCLUDE_DIR}/uhd + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/config.h b/host/include/uhd/config.h new file mode 100644 index 000000000..1d6cefcc0 --- /dev/null +++ b/host/include/uhd/config.h @@ -0,0 +1,82 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_CONFIG_H +#define INCLUDED_UHD_CONFIG_H + +#ifdef _MSC_VER +// Bring in "and", "or", and "not" +#include + +// Define ssize_t +#include +typedef ptrdiff_t ssize_t; + +#endif /* _MSC_VER */ + +// Define cross-platform macros +#if defined(_MSC_VER) + #define UHD_EXPORT __declspec(dllexport) + #define UHD_IMPORT __declspec(dllimport) + #define UHD_INLINE __forceinline + #define UHD_DEPRECATED __declspec(deprecated) + #define UHD_ALIGNED(x) __declspec(align(x)) + #define UHD_UNUSED(x) x +#elif defined(__MINGW32__) + #define UHD_EXPORT __declspec(dllexport) + #define UHD_IMPORT __declspec(dllimport) + #define UHD_INLINE inline + #define UHD_DEPRECATED __declspec(deprecated) + #define UHD_ALIGNED(x) __declspec(align(x)) + #define UHD_UNUSED(x) x __attribute__((unused)) +#elif defined(__GNUG__) && __GNUG__ >= 4 + #define UHD_EXPORT __attribute__((visibility("default"))) + #define UHD_IMPORT __attribute__((visibility("default"))) + #define UHD_INLINE inline __attribute__((always_inline)) + #define UHD_DEPRECATED __attribute__((deprecated)) + #define UHD_ALIGNED(x) __attribute__((aligned(x))) + #define UHD_UNUSED(x) x __attribute__((unused)) +#else + #define UHD_EXPORT + #define UHD_IMPORT + #define UHD_INLINE inline + #define UHD_DEPRECATED + #define UHD_ALIGNED(x) + #define UHD_UNUSED(x) x +#endif + +// API declaration macro +#ifdef UHD_DLL_EXPORTS + #define UHD_API UHD_EXPORT +#else + #define UHD_API UHD_IMPORT +#endif // UHD_DLL_EXPORTS + +// Platform defines for conditional code: +// Taken from boost/config/select_platform_config.hpp, +// However, we define macros, not strings, for platforms. +#if defined(linux) || defined(__linux) || defined(__linux__) + #define UHD_PLATFORM_LINUX +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define UHD_PLATFORM_WIN32 +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + #define UHD_PLATFORM_MACOS +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define UHD_PLATFORM_BSD +#endif + +#endif /* INCLUDED_UHD_CONFIG_H */ diff --git a/host/include/uhd/error.h b/host/include/uhd/error.h new file mode 100644 index 000000000..845d741dc --- /dev/null +++ b/host/include/uhd/error.h @@ -0,0 +1,136 @@ +/* + * 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 . + */ + +#ifndef INCLUDED_UHD_ERROR_H +#define INCLUDED_UHD_ERROR_H + +//! UHD error codes +/*! + * Each error code corresponds to a specific uhd::exception, with + * extra codes corresponding to a boost::exception, std::exception, + * and a catch-all for everything else. When an internal C++ function + * throws an exception, UHD converts it to one of these error codes + * to return on the C level. + */ +typedef enum { + + //! No error thrown. + UHD_ERROR_NONE = 0, + //! Invalid device arguments. + UHD_ERROR_INVALID_DEVICE = 1, + + //! See uhd::index_error. + UHD_ERROR_INDEX = 10, + //! See uhd::key_error. + UHD_ERROR_KEY = 11, + + //! See uhd::not_implemented_error. + UHD_ERROR_NOT_IMPLEMENTED = 20, + //! See uhd::usb_error. + UHD_ERROR_USB = 21, + + //! See uhd::io_error. + UHD_ERROR_IO = 30, + //! See uhd::os_error. + UHD_ERROR_OS = 31, + + //! See uhd::assertion_error. + UHD_ERROR_ASSERTION = 40, + //! See uhd::lookup_error. + UHD_ERROR_LOOKUP = 41, + //! See uhd::type_error. + UHD_ERROR_TYPE = 42, + //! See uhd::value_error. + UHD_ERROR_VALUE = 43, + //! See uhd::runtime_error. + UHD_ERROR_RUNTIME = 44, + //! See uhd::environment_error. + UHD_ERROR_ENVIRONMENT = 45, + //! See uhd::system_error. + UHD_ERROR_SYSTEM = 46, + //! See uhd::exception. + UHD_ERROR_EXCEPT = 47, + + //! A boost::exception was thrown. + UHD_ERROR_BOOSTEXCEPT = 60, + + //! A std::exception was thrown. + UHD_ERROR_STDEXCEPT = 70, + + //! An unknown error was thrown. + UHD_ERROR_UNKNOWN = 100 +} uhd_error; + +#ifdef __cplusplus +#include +#include + +#include + +UHD_API uhd_error error_from_uhd_exception(const uhd::exception* e); + +/*! + * This macro runs the given C++ code, and if there are any exceptions + * thrown, they are caught and converted to the corresponding UHD error + * code. + */ +#define UHD_SAFE_C(...) \ + try{ __VA_ARGS__ } \ + catch (const uhd::exception &e) { \ + return error_from_uhd_exception(&e); \ + } \ + catch (const boost::exception&) { \ + return UHD_ERROR_BOOSTEXCEPT; \ + } \ + catch (const std::exception&) { \ + return UHD_ERROR_STDEXCEPT; \ + } \ + catch (...) { \ + return UHD_ERROR_UNKNOWN; \ + } \ + return UHD_ERROR_NONE; + +/*! + * This macro runs the given C++ code, and if there are any exceptions + * thrown, they are caught and converted to the corresponding UHD error + * code. The error message is also saved into the given handle. + */ +#define UHD_SAFE_C_SAVE_ERROR(h, ...) \ + h->last_error.clear(); \ + try{ __VA_ARGS__ } \ + catch (const uhd::exception &e) { \ + h->last_error = e.what(); \ + return error_from_uhd_exception(&e); \ + } \ + catch (const boost::exception &e) { \ + h->last_error = boost::diagnostic_information(e); \ + return UHD_ERROR_BOOSTEXCEPT; \ + } \ + catch (const std::exception &e) { \ + h->last_error = e.what(); \ + return UHD_ERROR_STDEXCEPT; \ + } \ + catch (...) { \ + h->last_error = "Unrecognized exception caught."; \ + return UHD_ERROR_UNKNOWN; \ + } \ + h->last_error = "None"; \ + return UHD_ERROR_NONE; + +#endif + +#endif /* INCLUDED_UHD_ERROR_H */ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 2a25df35f..140b5c710 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -42,3 +42,16 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/types COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + metadata.h + ranges.h + sensors.h + tune_request.h + tune_result.h + usrp_info.h + DESTINATION ${INCLUDE_DIR}/uhd/types + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/types/metadata.h b/host/include/uhd/types/metadata.h new file mode 100644 index 000000000..0cdbc6a72 --- /dev/null +++ b/host/include/uhd/types/metadata.h @@ -0,0 +1,364 @@ +/* + * Copyright 2015 Ettus Research + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDED_UHD_TYPES_METADATA_H +#define INCLUDED_UHD_TYPES_METADATA_H + +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +#include +#include + +struct uhd_rx_metadata_t { + uhd::rx_metadata_t rx_metadata_cpp; + std::string last_error; +}; + +struct uhd_tx_metadata_t { + uhd::tx_metadata_t tx_metadata_cpp; + std::string last_error; +}; + +struct uhd_async_metadata_t { + uhd::async_metadata_t async_metadata_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_rx_metadata_t; +struct uhd_tx_metadata_t; +struct uhd_async_metadata_t; +#endif + +//! RX metadata interface for describing sent IF data. +/*! + * See uhd::rx_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_rx_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_rx_metadata_t* uhd_rx_metadata_handle; + +//! TX metadata interface for describing received IF data. +/*! + * See uhd::tx_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_tx_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_tx_metadata_t* uhd_tx_metadata_handle; + +//! Interface for describing transmit-related events. +/*! + * See uhd::async_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_async_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_async_metadata_t* uhd_async_metadata_handle; + +//! Error condition on a receive call +/*! + * See uhd::rx_metadata_t::error_code_t for more details. + */ +typedef enum { + //! No error code associated with this metadata + UHD_RX_METADATA_ERROR_CODE_NONE = 0x0, + //! No packet received, implementation timed out + UHD_RX_METADATA_ERROR_CODE_TIMEOUT = 0x1, + //! A stream command was issued in the past + UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND = 0x2, + //! Expected another stream command + UHD_RX_METADATA_ERROR_CODE_BROKEN_CHAIN = 0x4, + //! Overflow or sequence error + UHD_RX_METADATA_ERROR_CODE_OVERFLOW = 0x8, + //! Multi-channel alignment failed + UHD_RX_METADATA_ERROR_CODE_ALIGNMENT = 0xC, + //! The packet could not be parsed + UHD_RX_METADATA_ERROR_CODE_BAD_PACKET = 0xF +} uhd_rx_metadata_error_code_t; + + +//! Create a new RX metadata handle +UHD_API uhd_error uhd_rx_metadata_make( + uhd_rx_metadata_handle* handle +); + +//! Free an RX metadata handle +/*! + * Using a handle after freeing it here will result in a segmentation fault. + */ +UHD_API uhd_error uhd_rx_metadata_free( + uhd_rx_metadata_handle* handle +); + +//! Has time specification? +UHD_API uhd_error uhd_rx_metadata_has_time_spec( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Time of first sample +UHD_API uhd_error uhd_rx_metadata_time_spec( + uhd_rx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Fragmentation flag +UHD_API uhd_error uhd_rx_metadata_more_fragments( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Fragmentation offset +UHD_API uhd_error uhd_rx_metadata_fragment_offset( + uhd_rx_metadata_handle h, + size_t *fragment_offset_out +); + +//! Start of burst? +UHD_API uhd_error uhd_rx_metadata_start_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! End of burst? +UHD_API uhd_error uhd_rx_metadata_end_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Result out of sequence? +UHD_API uhd_error uhd_rx_metadata_out_of_sequence( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Return a pretty-print representation of this metadata. +/*! + * NOTE: This function will overwrite any string in the given buffer + * before inserting the pp_string. + * + * \param h metadata handle + * \param pp_string_out string buffer for pp_string + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_to_pp_string( + uhd_rx_metadata_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error state of the RX metadata object. +UHD_API uhd_error uhd_rx_metadata_error_code( + uhd_rx_metadata_handle h, + uhd_rx_metadata_error_code_t *error_code_out +); + +//! Get a string representation of the last error state of the RX metadata object. +/*! + * NOTES: + *
    + *
  • This is different from the error that can be retrieved with + * uhd_rx_metadata_last_error. See uhd::rx_metadata_t::strerror() for details.
  • + *
  • This function will overwrite any string in the given buffer before + * inserting the error string.
  • + *
+ * + * \param h metadata handle + * \param strerror_out string buffer for strerror + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_strerror( + uhd_rx_metadata_handle h, + char* strerror_out, + size_t strbuffer_len +); + +//! Get the last error logged by the RX metadata object. +/*! + * NOTES: + *
    + *
  • This is different from the error that can be retrieved with + * uhd_rx_metadata_strerror(). See for details.
  • + *
  • This function will overwrite any string in the given buffer before + * inserting the error string.
  • + *
+ * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_last_error( + uhd_rx_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Create a new TX metadata handle +UHD_API 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 +); + + +//! Free an TX metadata handle +/*! + * Using a handle after freeing it here will result in a segmentation fault. + */ +UHD_API uhd_error uhd_tx_metadata_free( + uhd_tx_metadata_handle* handle +); + +//! Has time specification? +UHD_API uhd_error uhd_tx_metadata_has_time_spec( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! Get time specification +UHD_API uhd_error uhd_tx_metadata_time_spec( + uhd_tx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Start of burst? +UHD_API uhd_error uhd_tx_metadata_start_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! End of burst? +UHD_API uhd_error uhd_tx_metadata_end_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! Get the last error logged by the TX metadata object. +/*! + * NOTE: This function will overwrite any string in the given buffer before + * inserting the error string. + * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_tx_metadata_last_error( + uhd_tx_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +//! The type of event for a receive async message call. +/*! + * See uhd::async_metadata_t::event_code_t for more details. + */ +typedef enum { + //! A burst was successfully transmitted. + UHD_ASYNC_METADATA_EVENT_CODE_BURST_ACK = 0x1, + //! An internal send buffer has emptied. + UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW = 0x2, + //! Packet loss error between host and device. + UHD_ASYNC_METADATA_EVENT_CODE_SEQ_ERROR = 0x4, + //! Packet had time that was late. + UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR = 0x8, + //! Underflow occurred inside a packet. + UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10, + //! Packet loss within a burst. + UHD_ASYNC_METADATA_EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20, + //! Some kind of custom user payload. + UHD_ASYNC_METADATA_EVENT_CODE_USER_PAYLOAD = 0x40 +} uhd_async_metadata_event_code_t; + +//! Create a new async metadata handle +UHD_API uhd_error uhd_async_metadata_make( + uhd_async_metadata_handle* handle +); + +//! Free an async metadata handle +/*! + * Using a handle after freeing it will result in a segmentation fault. + */ +UHD_API uhd_error uhd_async_metadata_free( + uhd_async_metadata_handle* handle +); + +//! Channel number in a MIMO configuration +UHD_API uhd_error uhd_async_metadata_channel( + uhd_async_metadata_handle h, + size_t *channel_out +); + +//! Has time specification? +UHD_API uhd_error uhd_async_metadata_has_time_spec( + uhd_async_metadata_handle h, + bool *result_out +); + +//! Get time specification +UHD_API uhd_error uhd_async_metadata_time_spec( + uhd_async_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Get last event code +UHD_API uhd_error uhd_async_metadata_event_code( + uhd_async_metadata_handle h, + uhd_async_metadata_event_code_t *event_code_out +); + +//! Get payload from custom FPGA fabric +UHD_API uhd_error uhd_async_metadata_user_payload( + uhd_async_metadata_handle h, + uint32_t user_payload_out[4] +); + +//! Get the last error logged by the async metadata object. +/*! + * NOTE: This function will overwrite any string in the given buffer before + * inserting the error string. + * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_async_metadata_last_error( + uhd_async_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_METADATA_H */ diff --git a/host/include/uhd/types/ranges.h b/host/include/uhd/types/ranges.h new file mode 100644 index 000000000..ca80c9141 --- /dev/null +++ b/host/include/uhd/types/ranges.h @@ -0,0 +1,154 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TYPES_RANGES_H +#define INCLUDED_UHD_TYPES_RANGES_H + +#include +#include + +#include +#include + +//! Range of floating-point values +typedef struct { + //! First value + double start; + //! Last value + double stop; + //! Granularity + double step; +} uhd_range_t; + +#ifdef __cplusplus +#include +#include + +struct uhd_meta_range_t { + uhd::meta_range_t meta_range_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_meta_range_t; +#endif + +//! C-level interface for dealing with a list of ranges +/*! + * See uhd::meta_range_t for more details. + */ +typedef struct uhd_meta_range_t* uhd_meta_range_handle; + +//! Get a string representation of the given range +UHD_API uhd_error uhd_range_to_pp_string( + const uhd_range_t *range, + char* pp_string_out, + size_t strbuffer_len +); + +//! Create a meta range handle +/*! + * NOTE: Using a uhd_meta_range_handle before passing it into this function will + * result in undefined behavior. + */ +UHD_API uhd_error uhd_meta_range_make( + uhd_meta_range_handle* h +); + +//! Destroy a meta range handle +/*! + * NOTE: Using a uhd_meta_range_handle after passing it into this function will + * result in a segmentation fault. + */ +UHD_API uhd_error uhd_meta_range_free( + uhd_meta_range_handle* h +); + +//! Get the overall start value for the given meta range +UHD_API uhd_error uhd_meta_range_start( + uhd_meta_range_handle h, + double *start_out +); + +//! Get the overall stop value for the given meta range +UHD_API uhd_error uhd_meta_range_stop( + uhd_meta_range_handle h, + double *stop_out +); + +//! Get the overall step value for the given meta range +UHD_API uhd_error uhd_meta_range_step( + uhd_meta_range_handle h, + double *step_out +); + +//! Clip the given value to a possible value in the given range +UHD_API uhd_error uhd_meta_range_clip( + uhd_meta_range_handle h, + double value, + bool clip_step, + double *result_out +); + +//! Get the number of ranges in the given meta range +UHD_API uhd_error uhd_meta_range_size( + uhd_meta_range_handle h, + size_t *size_out +); + +//! Add a range to the given meta range +UHD_API uhd_error uhd_meta_range_push_back( + uhd_meta_range_handle h, + const uhd_range_t *range +); + +//! Get the range at the given index +UHD_API uhd_error uhd_meta_range_at( + uhd_meta_range_handle h, + size_t num, + uhd_range_t *range_out +); + +//! Get a string representation of the given meta range +UHD_API uhd_error uhd_meta_range_to_pp_string( + uhd_meta_range_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error recorded by the underlying meta range +UHD_API uhd_error uhd_meta_range_last_error( + uhd_meta_range_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} + +UHD_API uhd::range_t uhd_range_c_to_cpp( + const uhd_range_t *range_c +); + +UHD_API void uhd_range_cpp_to_c( + const uhd::range_t &range_cpp, + uhd_range_t *range_c +); +#endif + +#endif /* INCLUDED_UHD_TYPES_RANGES_H */ diff --git a/host/include/uhd/types/sensors.h b/host/include/uhd/types/sensors.h new file mode 100644 index 000000000..c0037c9f6 --- /dev/null +++ b/host/include/uhd/types/sensors.h @@ -0,0 +1,231 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TYPES_SENSORS_H +#define INCLUDED_UHD_TYPES_SENSORS_H + +#include +#include + +#ifdef __cplusplus +#include +#include + +struct uhd_sensor_value_t { + // No default constructor, so we need a pointer + uhd::sensor_value_t* sensor_value_cpp; + std::string last_error; +}; +extern "C" { +#else +struct uhd_sensor_value_t; +#endif + +//! C-level interface for a UHD sensor +/*! + * See uhd::sensor_value_t for more details. + * + * NOTE: Using a handle before calling a make function will result in undefined behavior. + */ +typedef struct uhd_sensor_value_t* uhd_sensor_value_handle; + +//! Sensor value types +typedef enum { + UHD_SENSOR_VALUE_BOOLEAN = 98, + UHD_SENSOR_VALUE_INTEGER = 105, + UHD_SENSOR_VALUE_REALNUM = 114, + UHD_SENSOR_VALUE_STRING = 115 +} uhd_sensor_value_data_type_t; + +//! Make a UHD sensor from a boolean. +/*! + * \param h the sensor handle in which to place sensor + * \param name sensor name + * \param value sensor value + * \param utrue string representing "true" + * \param ufalse string representing "false" + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_bool( + uhd_sensor_value_handle* h, + const char* name, + bool value, + const char* utrue, + const char* ufalse +); + +//! Make a UHD sensor from an integer. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \param formatter printf-style format string for value string + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_int( + uhd_sensor_value_handle* h, + const char* name, + int value, + const char* unit, + const char* formatter +); + +//! Make a UHD sensor from a real number. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \param formatter printf-style format string for value string + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_realnum( + uhd_sensor_value_handle* h, + const char* name, + double value, + const char* unit, + const char* formatter +); + +//! Make a UHD sensor from a string. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_string( + uhd_sensor_value_handle* h, + const char* name, + const char* value, + const char* unit +); + +//! Free the given sensor handle. +/*! + * Attempting to use the handle after calling this handle will + * result in a segmentation fault. + */ +UHD_API uhd_error uhd_sensor_value_free( + uhd_sensor_value_handle* h +); + +//! Get the sensor's value as a boolean. +UHD_API uhd_error uhd_sensor_value_to_bool( + uhd_sensor_value_handle h, + bool *value_out +); + +//! Get the sensor's value as an integer. +UHD_API uhd_error uhd_sensor_value_to_int( + uhd_sensor_value_handle h, + int *value_out +); + +//! Get the sensor's value as a real number. +UHD_API uhd_error uhd_sensor_value_to_realnum( + uhd_sensor_value_handle h, + double *value_out +); + +//! Get the sensor's name. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor name. + * + * \param h sensor handle + * \param name_out string buffer in which to place name + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_name( + uhd_sensor_value_handle h, + char* name_out, + size_t strbuffer_len +); + +//! Get the sensor's value. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor value. + * + * \param h sensor handle + * \param value_out string buffer in which to place value + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_value( + uhd_sensor_value_handle h, + char* value_out, + size_t strbuffer_len +); + +//! Get the sensor's unit. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor unit. + * + * \param h sensor handle + * \param unit_out string buffer in which to place unit + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_unit( + uhd_sensor_value_handle h, + char* unit_out, + size_t strbuffer_len +); + +UHD_API uhd_error uhd_sensor_value_data_type( + uhd_sensor_value_handle h, + uhd_sensor_value_data_type_t *data_type_out +); + +//! Get a pretty-print representation of the given sensor. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the string. + * + * \param h sensor handle + * \param pp_string_out string buffer in which to place pp_string + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_to_pp_string( + uhd_sensor_value_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error logged by the sensor handle. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the error string. + * + * \param h sensor handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_last_error( + uhd_sensor_value_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_SENSORS_H */ diff --git a/host/include/uhd/types/stream_cmd.hpp b/host/include/uhd/types/stream_cmd.hpp index 3c34c9656..c24296bd6 100644 --- a/host/include/uhd/types/stream_cmd.hpp +++ b/host/include/uhd/types/stream_cmd.hpp @@ -1,19 +1,19 @@ -// -// Copyright 2010-2012 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 . -// +/* + * Copyright 2010-2012,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 . + */ #ifndef INCLUDED_UHD_TYPES_STREAM_CMD_HPP #define INCLUDED_UHD_TYPES_STREAM_CMD_HPP @@ -59,6 +59,6 @@ namespace uhd{ stream_cmd_t(const stream_mode_t &stream_mode); }; -} //namespace uhd +} /* namespace uhd */ #endif /* INCLUDED_UHD_TYPES_STREAM_CMD_HPP */ diff --git a/host/include/uhd/types/tune_request.h b/host/include/uhd/types/tune_request.h new file mode 100644 index 000000000..046350643 --- /dev/null +++ b/host/include/uhd/types/tune_request.h @@ -0,0 +1,61 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_REQUEST_H +#define INCLUDED_UHD_TYPES_TUNE_REQUEST_H + +#include + +#include + +//! Policy options for tunable elements in the RF chain. +typedef enum { + //! Do not set this argument, use current setting. + UHD_TUNE_REQUEST_POLICY_NONE = 78, + //! Automatically determine the argument's value. + UHD_TUNE_REQUEST_POLICY_AUTO = 65, + //! Use the argument's value for the setting. + UHD_TUNE_REQUEST_POLICY_MANUAL = 77 +} uhd_tune_request_policy_t; + +//! Instructs implementation how to tune the RF chain +/*! + * See uhd::tune_request_t for more details. + */ +typedef struct { + //! Target frequency for RF chain in Hz + double target_freq; + //! RF frequency policy + uhd_tune_request_policy_t rf_freq_policy; + //! RF frequency in Hz + double rf_freq; + //! DSP frequency policy + uhd_tune_request_policy_t dsp_freq_policy; + //! DSP frequency in Hz + double dsp_freq; + //! Key-value pairs delimited by commas + char* args; +} uhd_tune_request_t; + +#ifdef __cplusplus +#include + +UHD_API uhd::tune_request_t uhd_tune_request_c_to_cpp(uhd_tune_request_t *tune_request_c); + +#endif + +#endif /* INCLUDED_UHD_TYPES_TUNE_REQUEST_H */ diff --git a/host/include/uhd/types/tune_result.h b/host/include/uhd/types/tune_result.h new file mode 100644 index 000000000..e0d00cd2e --- /dev/null +++ b/host/include/uhd/types/tune_result.h @@ -0,0 +1,60 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_RESULT_H +#define INCLUDED_UHD_TYPES_TUNE_RESULT_H + +#include + +#include + +//! Stores RF and DSP tuned frequencies. +/*! + * See uhd::tune_result_t for more details. + */ +typedef struct { + //! Target RF frequency, clipped to be within system range + double clipped_rf_freq; + //! Target RF frequency, including RF FE offset + double target_rf_freq; + //! Frequency to which RF LO is actually tuned + double actual_rf_freq; + //! Frequency the CORDIC must adjust the RF + double target_dsp_freq; + //! Frequency to which the CORDIC in the DSP actually tuned + double actual_dsp_freq; +} uhd_tune_result_t; + +#ifdef __cplusplus +extern "C" { +#endif + +//! Create a pretty print representation of this tune result. +UHD_API void uhd_tune_result_to_pp_string(uhd_tune_result_t *tune_result, + char* pp_string_out, size_t strbuffer_len); + +#ifdef __cplusplus +} +#include + +UHD_API uhd::tune_result_t uhd_tune_result_c_to_cpp(uhd_tune_result_t *tune_result_c); + +UHD_API void uhd_tune_result_cpp_to_c(const uhd::tune_result_t &tune_result_cpp, + uhd_tune_result_t *tune_result_c); +#endif + +#endif /* INCLUDED_UHD_TYPES_TUNE_RESULT_H */ diff --git a/host/include/uhd/types/usrp_info.h b/host/include/uhd/types/usrp_info.h new file mode 100644 index 000000000..c118963da --- /dev/null +++ b/host/include/uhd/types/usrp_info.h @@ -0,0 +1,94 @@ +/* + * 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 . + */ + +#ifndef INCLUDED_UHD_TYPES_USRP_INFO_H +#define INCLUDED_UHD_TYPES_USRP_INFO_H + +#include +#include + +//! USRP RX info +/*! + * This struct is populated by uhd_usrp_get_rx_info(). + */ +typedef struct { + //! Motherboard ID + char* mboard_id; + //! Motherboard name + char* mboard_name; + //! Motherboard serial + char* mboard_serial; + //! RX daughterboard ID + char* rx_id; + //! RX subdev name + char* rx_subdev_name; + //! RX subdev spec + char* rx_subdev_spec; + //! RX daughterboard serial + char* rx_serial; + //! RX daughterboard antenna + char* rx_antenna; +} uhd_usrp_rx_info_t; + +//! USRP TX info +/*! + * This struct is populated by uhd_usrp_get_tx_info(). + */ +typedef struct { + //! Motherboard ID + char* mboard_id; + //! Motherboard name + char* mboard_name; + //! Motherboard serial + char* mboard_serial; + //! TX daughterboard ID + char* tx_id; + //! TX subdev name + char* tx_subdev_name; + //! TX subdev spec + char* tx_subdev_spec; + //! TX daughterboard serial + char* tx_serial; + //! TX daughterboard antenna + char* tx_antenna; +} uhd_usrp_tx_info_t; + +#ifdef __cplusplus +extern "C" { +#endif + +//! Clean up a uhd_usrp_rx_info_t populated by uhd_usrp_get_rx_info(). +/*! + * NOTE: If this function is passed a uhd_usrp_rx_info_t that has not + * been populated by uhd_usrp_get_rx_info(), it will produce a double-free + * error. + */ +UHD_API uhd_error uhd_usrp_rx_info_free(uhd_usrp_rx_info_t *rx_info); + +//! Clean up a uhd_usrp_tx_info_t populated by uhd_usrp_get_tx_info(). +/*! + * NOTE: If this function is passed a uhd_usrp_tx_info_t that has not + * been populated by uhd_usrp_get_tx_info(), it will produce a double-free + * error. + */ +UHD_API uhd_error uhd_usrp_tx_info_free(uhd_usrp_tx_info_t *tx_info); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_USRP_INFO_H */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index d30a2900a..e974f808d 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -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 @@ -15,7 +15,6 @@ # along with this program. If not, see . # - UHD_INSTALL(FILES #### dboard headers ### @@ -36,3 +35,14 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/usrp COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + dboard_eeprom.h + mboard_eeprom.h + subdev_spec.h + usrp.h + DESTINATION ${INCLUDE_DIR}/uhd/usrp + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/usrp/dboard_eeprom.h b/host/include/uhd/usrp/dboard_eeprom.h new file mode 100644 index 000000000..6980de0ce --- /dev/null +++ b/host/include/uhd/usrp/dboard_eeprom.h @@ -0,0 +1,110 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_USRP_DBOARD_EEPROM_H +#define INCLUDED_UHD_USRP_DBOARD_EEPROM_H + +#include +#include + +#ifdef __cplusplus +#include +#include + +struct uhd_dboard_eeprom_t { + uhd::usrp::dboard_eeprom_t dboard_eeprom_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_dboard_eeprom_t; +#endif + +//! A C-level interface for interacting with a daughterboard EEPROM +/*! + * See uhd::usrp::dboard_eeprom_t for more details. + * + * NOTE: Using a handle before passing it into uhd_dboard_eeprom_make() will + * result in undefined behavior. + */ +typedef struct uhd_dboard_eeprom_t* uhd_dboard_eeprom_handle; + +//! Create handle for a USRP daughterboard EEPROM +UHD_API uhd_error uhd_dboard_eeprom_make( + uhd_dboard_eeprom_handle* h +); + +//! Safely destroy the given handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_dboard_eeprom_free( + uhd_dboard_eeprom_handle* h +); + +//! Get the ID associated with the given daughterboard as a string hex representation +UHD_API uhd_error uhd_dboard_eeprom_get_id( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +); + +//! Set the daughterboard ID using a string hex representation +UHD_API uhd_error uhd_dboard_eeprom_set_id( + uhd_dboard_eeprom_handle h, + const char* id +); + +//! Get the daughterboard's serial +UHD_API uhd_error uhd_dboard_eeprom_get_serial( + uhd_dboard_eeprom_handle h, + char* serial_out, + size_t strbuffer_len +); + +//! Set the daughterboard's serial +UHD_API uhd_error uhd_dboard_eeprom_set_serial( + uhd_dboard_eeprom_handle h, + const char* serial +); + +//! Get the daughterboard's revision (not always present) +UHD_API uhd_error uhd_dboard_eeprom_get_revision( + uhd_dboard_eeprom_handle h, + int* revision_out +); + +//! Set the daughterboard's revision +UHD_API uhd_error uhd_dboard_eeprom_set_revision( + uhd_dboard_eeprom_handle h, + int revision +); + +//! Get the last error reported by the handle +UHD_API uhd_error uhd_dboard_eeprom_last_error( + uhd_dboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_DBOARD_EEPROM_H */ diff --git a/host/include/uhd/usrp/mboard_eeprom.h b/host/include/uhd/usrp/mboard_eeprom.h new file mode 100644 index 000000000..b4474a26d --- /dev/null +++ b/host/include/uhd/usrp/mboard_eeprom.h @@ -0,0 +1,87 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_USRP_MBOARD_EEPROM_H +#define INCLUDED_UHD_USRP_MBOARD_EEPROM_H + +#include +#include + +#ifdef __cplusplus +#include +#include + +struct uhd_mboard_eeprom_t { + uhd::usrp::mboard_eeprom_t mboard_eeprom_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_mboard_eeprom_t; +#endif + +//! A C-level interface for interacting with a USRP motherboard's EEPROM +/*! + * See uhd::usrp::mboard_eeprom_t for more details. + * + * NOTE: Using a handle before passing it into uhd_mboard_eeprom_make() will + * result in undefined behavior. + */ +typedef struct uhd_mboard_eeprom_t* uhd_mboard_eeprom_handle; + +//! Create a handle for working with a USRP motherboard EEPROM +UHD_API uhd_error uhd_mboard_eeprom_make( + uhd_mboard_eeprom_handle* h +); + +//! Free a USRP motherboard EEPROM handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_mboard_eeprom_free( + uhd_mboard_eeprom_handle* h +); + +//! Get the value associated with the given EEPROM key +UHD_API uhd_error uhd_mboard_eeprom_get_value( + uhd_mboard_eeprom_handle h, + const char* key, + char* value_out, + size_t strbuffer_len +); + +//! Set the value for the given EEPROM key +UHD_API uhd_error uhd_mboard_eeprom_set_value( + uhd_mboard_eeprom_handle h, + const char* key, + const char* value +); + +//! Get the last error recorded by the handle +UHD_API uhd_error uhd_mboard_eeprom_last_error( + uhd_mboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_MBOARD_EEPROM_H */ diff --git a/host/include/uhd/usrp/subdev_spec.h b/host/include/uhd/usrp/subdev_spec.h new file mode 100644 index 000000000..f847181b7 --- /dev/null +++ b/host/include/uhd/usrp/subdev_spec.h @@ -0,0 +1,137 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_USRP_SUBDEV_SPEC_H +#define INCLUDED_UHD_USRP_SUBDEV_SPEC_H + +#include +#include + +#include + +//! Subdevice specification +typedef struct { + // Daughterboard slot name + char* db_name; + //! Subdevice name + char* sd_name; +} uhd_subdev_spec_pair_t; + +#ifdef __cplusplus +#include +#include + +struct uhd_subdev_spec_t { + uhd::usrp::subdev_spec_t subdev_spec_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_subdev_spec_t; +#endif + +//! A C-level interface for working with a list of subdevice specifications +/*! + * See uhd::usrp::subdev_spec_t for more details. + * + * NOTE: Using a handle before passing it into uhd_subdev_spec_make() will result in + * undefined behavior. + */ +typedef struct uhd_subdev_spec_t* uhd_subdev_spec_handle; + +//! Safely destroy any memory created in the generation of a uhd_subdev_spec_pair_t +UHD_API uhd_error uhd_subdev_spec_pair_free( + uhd_subdev_spec_pair_t *subdev_spec_pair +); + +//! Check to see if two subdevice specifications are equal +UHD_API uhd_error uhd_subdev_spec_pairs_equal( + const uhd_subdev_spec_pair_t* first, + const uhd_subdev_spec_pair_t* second, + bool *result_out +); + +//! Create a handle for a list of subdevice specifications +UHD_API uhd_error uhd_subdev_spec_make( + uhd_subdev_spec_handle* h, + const char* markup +); + +//! Safely destroy a subdevice specification handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_subdev_spec_free( + uhd_subdev_spec_handle* h +); + +//! Check how many subdevice specifications are in this list +UHD_API uhd_error uhd_subdev_spec_size( + uhd_subdev_spec_handle h, + size_t *size_out +); + +//! Add a subdevice specification to this list +UHD_API uhd_error uhd_subdev_spec_push_back( + uhd_subdev_spec_handle h, + const char* markup +); + +//! Get the subdevice specification at the given index +UHD_API uhd_error uhd_subdev_spec_at( + uhd_subdev_spec_handle h, + size_t num, + uhd_subdev_spec_pair_t *subdev_spec_pair_out +); + +//! Get a string representation of the given list +UHD_API uhd_error uhd_subdev_spec_to_pp_string( + uhd_subdev_spec_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get a markup string representation of the given list +UHD_API uhd_error uhd_subdev_spec_to_string( + uhd_subdev_spec_handle h, + char* string_out, + size_t strbuffer_len +); + +//! Get the last error recorded by the given handle +UHD_API uhd_error uhd_subdev_spec_last_error( + uhd_subdev_spec_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} + +UHD_API uhd::usrp::subdev_spec_pair_t uhd_subdev_spec_pair_c_to_cpp( + const uhd_subdev_spec_pair_t* subdev_spec_pair_c +); + +UHD_API 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 +); +#endif + +#endif /* INCLUDED_UHD_USRP_SUBDEV_SPEC_H */ diff --git a/host/include/uhd/usrp/usrp.h b/host/include/uhd/usrp/usrp.h new file mode 100644 index 000000000..e828628c7 --- /dev/null +++ b/host/include/uhd/usrp/usrp.h @@ -0,0 +1,1242 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_USRP_H +#define INCLUDED_UHD_USRP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Streamers + */ + +//! A struct of parameters to construct a stream. +/*! + * See uhd::stream_args_t for more details. + */ +typedef struct { + //! Format of host memory + char* cpu_format; + //! Over-the-wire format + char* otw_format; + //! Other stream args + char* args; + //! Array that lists channels + size_t* channel_list; + //! Number of channels + int n_channels; +} uhd_stream_args_t; + +//! How streaming is issued to the device +/*! + * See uhd::stream_cmd_t for more details. + */ +typedef enum { + //! Stream samples indefinitely + UHD_STREAM_MODE_START_CONTINUOUS = 97, + //! End continuous streaming + UHD_STREAM_MODE_STOP_CONTINUOUS = 111, + //! Stream some number of samples and finish + UHD_STREAM_MODE_NUM_SAMPS_AND_DONE = 100, + //! Stream some number of samples but expect more + UHD_STREAM_MODE_NUM_SAMPS_AND_MORE = 109 +} uhd_stream_mode_t; + +//! Define how device streams to host +/*! + * See uhd::stream_cmd_t for more details. + */ +typedef struct { + //! How streaming is issued to the device + uhd_stream_mode_t stream_mode; + //! Number of samples + size_t num_samps; + //! Stream now? + bool stream_now; + //! If not now, then full seconds into future to stream + time_t time_spec_full_secs; + //! If not now, then fractional seconds into future to stream + double time_spec_frac_secs; +} uhd_stream_cmd_t; + +struct uhd_rx_streamer; +struct uhd_tx_streamer; + +//! C-level interface for working with an RX streamer +/*! + * See uhd::rx_streamer for more details. + */ +typedef struct uhd_rx_streamer* uhd_rx_streamer_handle; + +//! C-level interface for working with a TX streamer +/*! + * See uhd::tx_streamer for more details. + */ +typedef struct uhd_tx_streamer* uhd_tx_streamer_handle; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * RX Streamer + */ + +//! Create an RX streamer handle. +/*! + * NOTE: Using this streamer before passing it into uhd_usrp_get_rx_stream() + * will result in undefined behavior. + */ +UHD_API uhd_error uhd_rx_streamer_make( + uhd_rx_streamer_handle *h +); + +//! Free an RX streamer handle. +/*! + * NOTE: Using a streamer after passing it into this function will result + * in a segmentation fault. + */ +UHD_API uhd_error uhd_rx_streamer_free( + uhd_rx_streamer_handle *h +); + +//! Get the number of channels associated with this streamer +UHD_API uhd_error uhd_rx_streamer_num_channels( + uhd_rx_streamer_handle h, + size_t *num_channels_out +); + +//! Get the max number of samples per buffer per packet +UHD_API uhd_error uhd_rx_streamer_max_num_samps( + uhd_rx_streamer_handle h, + size_t *max_num_samps_out +); + +//! Receive buffers containing samples into the given RX streamer +/*! + * See uhd::rx_streamer::recv() for more details. + * + * \param h RX streamer handle + * \param buffs pointer to buffers in which to receive samples + * \param samps_per_buffer max number of samples per buffer + * \param md handle to RX metadata in which to receive results + * \param timeout timeout in seconds to wait for a packet + * \param one_packet send a single packet + * \param items_recvd pointer to output variable for number of samples received + */ +UHD_API 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 +); + +//! Issue the given stream command +/*! + * See uhd::rx_streamer::issue_stream_cmd() for more details. + */ +UHD_API uhd_error uhd_rx_streamer_issue_stream_cmd( + uhd_rx_streamer_handle h, + const uhd_stream_cmd_t *stream_cmd +); + +//! Get the last error reported by the RX streamer +/*! + * NOTE: This will overwrite the string currently in error_out before + * using it to return its error. + * + * \param h RX streamer handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer size + */ +UHD_API uhd_error uhd_rx_streamer_last_error( + uhd_rx_streamer_handle h, + char* error_out, + size_t strbuffer_len +); + +/* + * TX Streamer + */ + +//! Create an TX streamer handle. +/*! + * NOTE: Using this streamer before passing it into uhd_usrp_get_tx_stream() + * will result in undefined behavior. + */ +UHD_API uhd_error uhd_tx_streamer_make( + uhd_tx_streamer_handle *h +); + +//! Free an TX streamer handle. +/*! + * NOTE: Using a streamer after passing it into this function will result + * in a segmentation fault. + */ +UHD_API uhd_error uhd_tx_streamer_free( + uhd_tx_streamer_handle *h +); + +//! Get the number of channels associated with this streamer +UHD_API uhd_error uhd_tx_streamer_num_channels( + uhd_tx_streamer_handle h, + size_t *num_channels_out +); + +//! Get the max number of samples per buffer per packet +UHD_API uhd_error uhd_tx_streamer_max_num_samps( + uhd_tx_streamer_handle h, + size_t *max_num_samps_out +); + +//! Send buffers containing samples described by the metadata +/*! + * See uhd::tx_streamer::send() for more details. + * + * \param h TX streamer handle + * \param buffs pointer to buffers containing samples to send + * \param samps_per_buffer max number of samples per buffer + * \param md handle to TX metadata + * \param timeout timeout in seconds to wait for a packet + * \param items_sent pointer to output variable for number of samples send + */ +UHD_API uhd_error uhd_tx_streamer_send( + uhd_tx_streamer_handle h, + const void **buffs, + size_t samps_per_buff, + uhd_tx_metadata_handle md, + double timeout, + size_t *items_sent +); + +//! Receive an asynchronous message from this streamer +/*! + * See uhd::tx_streamer::recv_async_msg() for more details. + */ +UHD_API uhd_error uhd_tx_streamer_recv_async_msg( + uhd_tx_streamer_handle h, + uhd_async_metadata_handle md, + double timeout, + bool *valid +); + +//! Get the last error reported by the TX streamer +/*! + * NOTE: This will overwrite the string currently in error_out before + * using it to return its error. + * + * \param h TX streamer handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer size + */ +UHD_API uhd_error uhd_tx_streamer_last_error( + uhd_tx_streamer_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +/**************************************************************************** + * Public Datatypes for USRP / streamer handling. + ***************************************************************************/ +struct uhd_usrp; + +//! C-level interface for working with a USRP device +/* + * See uhd::usrp::multi_usrp for more details. + * + * NOTE: You must pass this handle into uhd_usrp_make before using it. + */ +typedef struct uhd_usrp* uhd_usrp_handle; + +/**************************************************************************** + * USRP Make / Free API calls + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +//! Create a USRP handle. +/*! + * \param h the handle + * \param args device args (e.g. "type=x300") + */ +UHD_API uhd_error uhd_usrp_make( + uhd_usrp_handle *h, + const char *args +); + +//! Safely destroy the USRP object underlying the handle. +/*! + * NOTE: Attempting to use a USRP handle after passing it into this function + * will result in a segmentation fault. + */ +UHD_API uhd_error uhd_usrp_free( + uhd_usrp_handle *h +); + +//! Get the last error reported by the USRP handle +UHD_API uhd_error uhd_usrp_last_error( + uhd_usrp_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Create RX streamer from a USRP handle and given stream args +UHD_API uhd_error uhd_usrp_get_rx_stream( + uhd_usrp_handle h, + uhd_stream_args_t *stream_args, + uhd_rx_streamer_handle h_out +); + +//! Create TX streamer from a USRP handle and given stream args +UHD_API uhd_error uhd_usrp_get_tx_stream( + uhd_usrp_handle h, + uhd_stream_args_t *stream_args, + uhd_tx_streamer_handle h_out +); + +/**************************************************************************** + * multi_usrp API calls + ***************************************************************************/ + +//! Get RX info from the USRP device +/*! + * NOTE: After calling this function, uhd_usrp_rx_info_free() must be called on info_out. + */ +UHD_API uhd_error uhd_usrp_get_rx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_rx_info_t *info_out +); + +//! Get TX info from the USRP device +/*! + * NOTE: After calling this function, uhd_usrp_tx_info_free() must be called on info_out. + */ +UHD_API uhd_error uhd_usrp_get_tx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_tx_info_t *info_out +); + +/**************************************************************************** + * Motherboard methods + ***************************************************************************/ + +//! Set the master clock rate. +/*! + * See uhd::usrp::multi_usrp::set_master_clock_rate() for more details. + */ +UHD_API uhd_error uhd_usrp_set_master_clock_rate( + uhd_usrp_handle h, + double rate, + size_t mboard +); + +//! Get the master clock rate. +/*! + * See uhd::usrp::multi_usrp::get_master_clock_rate() for more details. + */ +UHD_API uhd_error uhd_usrp_get_master_clock_rate( + uhd_usrp_handle h, + size_t mboard, + double *clock_rate_out +); + +//! Get a pretty-print representation of the USRP device. +/*! + * See uhd::usrp::multi_usrp::get_pp_string() for more details. + */ +UHD_API uhd_error uhd_usrp_get_pp_string( + uhd_usrp_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the motherboard name for the given device +/*! + * See uhd::usrp::multi_usrp::get_mboard_name() for more details. + */ +UHD_API uhd_error uhd_usrp_get_mboard_name( + uhd_usrp_handle h, + size_t mboard, + char* mboard_name_out, + size_t strbuffer_len +); + +//! Get the USRP device's current internal time +/*! + * See uhd::usrp::multi_usrp::get_time_now() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_now( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Get the time when this device's last PPS pulse occurred +/*! + * See uhd::usrp::multi_usrp::get_time_last_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_last_pps( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Set the USRP device's time +/*! + * See uhd::usrp::multi_usrp::set_time_now() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_now( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Set the USRP device's time to the given value upon the next PPS detection +/*! + * See uhd::usrp::multi_usrp::set_time_next_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_next_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Synchronize the time across all motherboards +/*! + * See uhd::usrp::multi_usrp::set_time_unknown_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_unknown_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs +); + +//! Are all motherboard times synchronized? +UHD_API uhd_error uhd_usrp_get_time_synchronized( + uhd_usrp_handle h, + bool *result_out +); + +//! Set the time at which timed commands will take place +/*! + * See uhd::usrp::multi_usrp::set_command_time() for more details. + */ +UHD_API uhd_error uhd_usrp_set_command_time( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Clear the command time so that commands are sent ASAP +UHD_API uhd_error uhd_usrp_clear_command_time( + uhd_usrp_handle h, + size_t mboard +); + +//! Issue a stream command to tell the device to send samples to the host +/*! + * See uhd::usrp::multi_usrp::issue_stream_command() for more details. + */ +UHD_API uhd_error uhd_usrp_issue_stream_cmd( + uhd_usrp_handle h, + uhd_stream_cmd_t *stream_cmd, + size_t chan +); + +//! Set the time source for the given device +/*! + * See uhd::usrp::multi_usrp::set_time_source() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_source( + uhd_usrp_handle h, + const char* time_source, + size_t mboard +); + +//! Get the time source for the given device +/*! + * See uhd::usrp::multi_usrp::get_time_source() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_source( + uhd_usrp_handle h, + size_t mboard, + char* time_source_out, + size_t strbuffer_len +); + +//! Get a list of time sources for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of time sources. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param time_sources_out string buffer in which to place time sources + * \param strbuffer_len buffer length + * \param num_time_sources_out variable in which to place number of time sources + */ +UHD_API 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 +); + +//! Set the given device's clock source +/*! + * See uhd::usrp::multi_usrp::set_clock_source() for more details. + */ +UHD_API uhd_error uhd_usrp_set_clock_source( + uhd_usrp_handle h, + const char* clock_source, + size_t mboard +); + +//! Get the given device's clock source +/*! + * See uhd::usrp::multi_usrp::get_clock_source() for more details. + */ +UHD_API uhd_error uhd_usrp_get_clock_source( + uhd_usrp_handle h, + size_t mboard, + char* clock_source_out, + size_t strbuffer_len +); + +//! Get a list of clock sources for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of clock sources. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param clock_sources_out string buffer in which to place clock sources + * \param strbuffer_len buffer length + * \param num_clock_sources_out variable in which to place number of clock sources + */ +UHD_API 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 +); + +//! Enable or disable sending the clock source to an output connector +/*! + * See uhd::usrp::set_clock_source_out() for more details. + */ +UHD_API uhd_error uhd_usrp_set_clock_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +); + +//! Enable or disable sending the time source to an output connector +/*! + * See uhd::usrp::set_time_source_out() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +); + +//! Get the number of devices associated with the given USRP handle +UHD_API uhd_error uhd_usrp_get_num_mboards( + uhd_usrp_handle h, + size_t *num_mboards_out +); + +//! Get the value associated with the given sensor name +UHD_API uhd_error uhd_usrp_get_mboard_sensor( + uhd_usrp_handle h, + const char* name, + size_t mboard, + uhd_sensor_value_handle sensor_value_out +); + +//! Get a list of motherboard sensors for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of motherboard sensors. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param mboard_sensors_out string buffer in which to place motherboard sensors + * \param strbuffer_len buffer length + * \param num_mboard_sensors_out variable in which to place number of motherboard sensors + */ +UHD_API 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 +); + +//! Perform a write on a user configuration register bus +/*! + * See uhd::usrp::multi_usrp::set_user_register() for more details. + */ +UHD_API uhd_error uhd_usrp_set_user_register( + uhd_usrp_handle h, + uint8_t addr, + uint32_t data, + size_t mboard +); + +/**************************************************************************** + * EEPROM access methods + ***************************************************************************/ + +//! Get a handle for the given motherboard's EEPROM +UHD_API uhd_error uhd_usrp_get_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +); + +//! Set values in the given motherboard's EEPROM +UHD_API uhd_error uhd_usrp_set_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +); + +//! Get a handle for the given device's daughterboard EEPROM +UHD_API 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 +); + +//! Set values in the given daughterboard's EEPROM +UHD_API 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 +); + +/**************************************************************************** + * RX methods + ***************************************************************************/ + +//! Map the given device's RX frontend to a channel +/*! + * See uhd::usrp::multi_usrp::set_rx_subdev_spec() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +); + +//! Get the RX frontend specfication for the given device +UHD_API uhd_error uhd_usrp_get_rx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +); + +//! Get the number of RX channels for the given handle +UHD_API uhd_error uhd_usrp_get_rx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +); + +//! Get the name for the RX frontend +UHD_API uhd_error uhd_usrp_get_rx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* rx_subdev_name_out, + size_t strbuffer_len +); + +//! Set the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_set_rx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +); + +//! Get the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_get_rx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +); + +//! Get a range of possible RX rates for the given channel +UHD_API uhd_error uhd_usrp_get_rx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +); + +//! Set the given channel's center RX frequency +UHD_API 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 +); + +//! Get the given channel's center RX frequency +UHD_API uhd_error uhd_usrp_get_rx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +); + +//! Get all possible center frequency ranges for the given channel +/*! + * See uhd::usrp::multi_usrp::get_rx_freq_range() for more details. + */ +UHD_API uhd_error uhd_usrp_get_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Get all possible RF frequency ranges for the given channel's RX RF frontend +UHD_API uhd_error uhd_usrp_get_fe_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Set the RX gain for the given channel and name +UHD_API uhd_error uhd_usrp_set_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +); + +//! Set the normalized RX gain [0.0, 1.0] for the given channel +/*! + * See uhd::usrp::multi_usrp::set_normalized_rx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_set_normalized_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +); + +//! Enable or disable the given channel's RX AGC module +/*! + * See uhd::usrp::multi_usrp::set_rx_agc() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_agc( + uhd_usrp_handle h, + bool enable, + size_t chan +); + +//! Get the given channel's RX gain +UHD_API uhd_error uhd_usrp_get_rx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +); + +//! Get the given channel's normalized RX gain [0.0, 1.0] +/*! + * See uhd::usrp::multi_usrp::get_normalized_rx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_get_normalized_rx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +); + +//! Get all possible gain ranges for the given channel and name +UHD_API 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 +); + +//! Get a list of RX gain names for the given channel +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param rx_gain_names_out string buffer in which to place RX gain names + * \param strbuffer_len buffer length + * \param num_rx_gain_names_out variable in which to place number of RX gain names + */ +UHD_API 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 +); + +//! Set the RX antenna for the given channel +UHD_API uhd_error uhd_usrp_set_rx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +); + +//! Get the RX antenna for the given channel +UHD_API uhd_error uhd_usrp_get_rx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +); + +//! Get a list of RX antennas associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param rx_antennas_out string buffer in which to place RX antennas + * \param strbuffer_len buffer length + * \param num_rx_antennas_out variable in which to place number of RX gain names + */ +UHD_API 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 +); + +//! Get a list of RX sensors associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param sensor_names_out string buffer in which to place RX sensor names + * \param strbuffer_len buffer length + * \param num_rx_sensors_out variable in which to place number of RX sensor names + */ +UHD_API 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 +); + +//! Set the bandwidth for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_set_rx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +); + +//! Get the bandwidth for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_get_rx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +); + +//! Get all possible bandwidth ranges for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_get_rx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +); + +//! Get the value for the given RX sensor +UHD_API uhd_error uhd_usrp_get_rx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +); + +//! Enable or disable RX DC offset correction for the given channel +/*! + * See uhd::usrp::multi_usrp::set_rx_dc_offset() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +//! Enable or disable RX IQ imbalance correction for the given channel +UHD_API uhd_error uhd_usrp_set_rx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +/**************************************************************************** + * TX methods + ***************************************************************************/ + +//! Map the given device's TX frontend to a channel +/*! + * See uhd::usrp::multi_usrp::set_tx_subdev_spec() for more details. + */ +UHD_API uhd_error uhd_usrp_set_tx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +); + +//! Get the TX frontend specfication for the given device +UHD_API uhd_error uhd_usrp_get_tx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +); + +//! Get the number of TX channels for the given handle +UHD_API uhd_error uhd_usrp_get_tx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +); + +//! Get the name for the RX frontend +UHD_API uhd_error uhd_usrp_get_tx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* tx_subdev_name_out, + size_t strbuffer_len +); + +//! Set the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_set_tx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +); + +//! Get the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_get_tx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +); + +//! Get a range of possible RX rates for the given channel +UHD_API uhd_error uhd_usrp_get_tx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +); + +//! Set the given channel's center TX frequency +UHD_API 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 +); + +//! Get the given channel's center TX frequency +UHD_API uhd_error uhd_usrp_get_tx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +); + +//! Get all possible center frequency ranges for the given channel +/*! + * See uhd::usrp::multi_usrp::get_rx_freq_range() for more details. + */ +UHD_API uhd_error uhd_usrp_get_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Get all possible RF frequency ranges for the given channel's TX RF frontend +UHD_API uhd_error uhd_usrp_get_fe_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Set the TX gain for the given channel and name +UHD_API uhd_error uhd_usrp_set_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +); + +//! Set the normalized TX gain [0.0, 1.0] for the given channel +/*! + * See uhd::usrp::multi_usrp::set_normalized_tx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_set_normalized_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +); + +//! Get all possible gain ranges for the given channel and name +UHD_API 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 +); + +//! Get the given channel's RX gain +UHD_API uhd_error uhd_usrp_get_tx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +); + +//! Get the given channel's normalized TX gain [0.0, 1.0] +/*! + * See uhd::usrp::multi_usrp::get_normalized_tx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_get_normalized_tx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +); + +//! Get a list of TX gain names for the given channel +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param tx_gain_names_out string buffer in which to place TX gain names + * \param strbuffer_len buffer length + * \param num_tx_gain_names_out variable in which to place number of TX gain names + */ +UHD_API 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 +); + +//! Set the TX antenna for the given channel +UHD_API uhd_error uhd_usrp_set_tx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +); + +//! Get the TX antenna for the given channel +UHD_API uhd_error uhd_usrp_get_tx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +); + +//! Get a list of tx antennas associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of tx gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param tx_antennas_out string buffer in which to place TX antennas + * \param strbuffer_len buffer length + * \param num_tx_antennas_out variable in which to place number of TX gain names + */ +UHD_API 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 +); + +//! Set the bandwidth for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_set_tx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +); + +//! Get the bandwidth for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_get_tx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +); + +//! Get all possible bandwidth ranges for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_get_tx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +); + +//! Get the value for the given TX sensor +UHD_API uhd_error uhd_usrp_get_tx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +); + +//! Get a list of TX sensors associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param sensor_names_out string buffer in which to place TX sensor names + * \param strbuffer_len buffer length + * \param num_tx_sensors_out variable in which to place number of TX sensor names + */ +UHD_API 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 +); + +//! Enable or disable TX DC offset correction for the given channel +/*! + * See uhd::usrp::multi_usrp::set_tx_dc_offset() for more details. + */ +UHD_API uhd_error uhd_usrp_set_tx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +//! Enable or disable TX IQ imbalance correction for the given channel +UHD_API uhd_error uhd_usrp_set_tx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +/**************************************************************************** + * GPIO methods + ***************************************************************************/ + +//! Get a list of GPIO banks associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param gpio_banks_out string buffer in which to place GPIO banks + * \param strbuffer_len buffer length + * \param num_gpio_banks_out variable in which to place number of GPIO banks + */ +UHD_API uhd_error uhd_usrp_get_gpio_banks( + uhd_usrp_handle h, + size_t mboard, + char* gpio_banks_out, + size_t strbuffer_len, + size_t *num_gpio_banks_out +); + +//! Set a GPIO attribute for a given GPIO bank +/*! + * See uhd::usrp::multi_usrp::set_gpio_attr() for more details. + */ +UHD_API 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 +); + +//! Get a GPIO attribute on a particular GPIO bank +/*! + * See uhd::usrp::multi_usrp::get_gpio_attr() for more details. + */ +UHD_API uhd_error uhd_usrp_get_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + size_t mboard, + uint32_t *attr_out +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_H */ diff --git a/host/include/uhd/usrp_clock/CMakeLists.txt b/host/include/uhd/usrp_clock/CMakeLists.txt index a116e4982..518cb7737 100644 --- a/host/include/uhd/usrp_clock/CMakeLists.txt +++ b/host/include/uhd/usrp_clock/CMakeLists.txt @@ -21,3 +21,9 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/usrp_clock COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + usrp_clock.h + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/usrp_clock/usrp_clock.h b/host/include/uhd/usrp_clock/usrp_clock.h new file mode 100644 index 000000000..2f5a1db29 --- /dev/null +++ b/host/include/uhd/usrp_clock/usrp_clock.h @@ -0,0 +1,117 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_USRP_CLOCK_H +#define INCLUDED_UHD_USRP_CLOCK_H + +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Public Datatypes for USRP clock + ***************************************************************************/ +struct uhd_usrp_clock; + +//! A C-level interface for interacting with an Ettus Research clock device +/*! + * See uhd::usrp_clock::multi_usrp_clock for more details. + * + * NOTE: Attempting to use a handle before passing it into uhd_usrp_clock_make() + * will result in undefined behavior. + */ +typedef struct uhd_usrp_clock* uhd_usrp_clock_handle; + +/**************************************************************************** + * Make / Free API calls + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/*! Create a USRP Clock handle. + * + * \param h The handle + * \param args Device args (e.g. "addr=192.168.10.3") + */ +UHD_API uhd_error uhd_usrp_clock_make( + uhd_usrp_clock_handle *h, + const char *args +); + +/*! Safely destroy the USRP_CLOCK object underlying the handle. + * + * Note: After calling this, usage of h may cause segmentation faults. + * However, multiple calling of uhd_usrp_free() is safe. + */ +UHD_API uhd_error uhd_usrp_clock_free( + uhd_usrp_clock_handle *h +); + +//! Get last error +UHD_API uhd_error uhd_usrp_clock_last_error( + uhd_usrp_clock_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Get board information in a nice output +UHD_API uhd_error uhd_usrp_clock_get_pp_string( + uhd_usrp_clock_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get number of boards +UHD_API uhd_error uhd_usrp_clock_get_num_boards( + uhd_usrp_clock_handle h, + size_t *num_boards_out +); + +//! Get time +UHD_API uhd_error uhd_usrp_clock_get_time( + uhd_usrp_clock_handle h, + size_t board, + uint32_t *clock_time_out +); + +//! Get sensor +UHD_API 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 +); + +//! Get sensor names +UHD_API 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 +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_CLOCK_H */ diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index 6b3d5a581..af6d3ee47 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -42,3 +42,11 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/utils COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + thread_priority.h + DESTINATION ${INCLUDE_DIR}/uhd/utils + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/utils/thread_priority.h b/host/include/uhd/utils/thread_priority.h new file mode 100644 index 000000000..217d7a1cc --- /dev/null +++ b/host/include/uhd/utils/thread_priority.h @@ -0,0 +1,53 @@ +// +// 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 . +// + +#ifndef INCLUDED_UHD_UTILS_THREAD_PRIORITY_H +#define INCLUDED_UHD_UTILS_THREAD_PRIORITY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static const float uhd_default_thread_priority = 0.5; + +/*! + * Set the scheduling priority on the current thread. + * + * A new thread or calling process should make this call + * with the defailts this to enable realtime scheduling. + * + * A priority of zero corresponds to normal priority. + * Positive priority values are higher than normal. + * Negative priority values are lower than normal. + * + * \param priority a value between -1 and 1 + * \param realtime true to use realtime mode + * \return UHD error code + */ +UHD_API uhd_error uhd_set_thread_priority( + float priority, + bool realtime +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_UTILS_THREAD_PRIORITY_H */ 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/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 . +// + +#include +#include + +#define MAP_TO_ERROR(exception_type, error_type) \ + if (dynamic_cast(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/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index 5e97628f0..d8938c8a8 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -94,3 +94,13 @@ 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}/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/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 . +// + +#include + +#include + +#include + +/* + * 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 . +// + +#include + +#include + +/* + * 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 . +// + +#include + +#include + +#include +#include +#include + +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 . +// + +#include +#include + +#include + +#include +#include +#include + +/* + * 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 . +// + +#include + +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/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 . +// + +#include +#include + +#include + +#include + +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(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(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/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 . +// + +#include + +#include + +#include + +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 . +// + +#include + +#include + +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/usrp_c.cpp b/host/lib/usrp/usrp_c.cpp new file mode 100644 index 000000000..3eaf70405 --- /dev/null +++ b/host/lib/usrp/usrp_c.cpp @@ -0,0 +1,1509 @@ +/* + * 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 . + */ + +/* C-Interface for multi_usrp */ + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * 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 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 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_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 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 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 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 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 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(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(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(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(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 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 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 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 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 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 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 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_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/usrp_clock_c.cpp b/host/lib/usrp_clock/usrp_clock_c.cpp new file mode 100644 index 000000000..b55abc852 --- /dev/null +++ b/host/lib/usrp_clock/usrp_clock_c.cpp @@ -0,0 +1,175 @@ +/* + * 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 . + */ + +/* C-Interface for multi_usrp_clock */ + +#include +#include + +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * 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 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_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 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 . +// + +#include +#include +#include +#include +#include +#include +#include + +uhd_error uhd_set_thread_priority( + float priority, + bool realtime +){ + UHD_SAFE_C( + uhd::set_thread_priority(priority, realtime); + ) +} diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 1fb1a1951..009509286 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -53,6 +53,16 @@ ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN) SET(UHD_TEST_TARGET_DEPS uhd) SET(UHD_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS}) +IF(ENABLE_C_API) + LIST(APPEND test_sources + eeprom_c_test.c + error_c_test.cpp + ranges_c_test.c + sensors_c_test.c + subdev_spec_c_test.c + ) +ENDIF(ENABLE_C_API) + #for each source: build an executable, register it as a test FOREACH(test_source ${test_sources}) GET_FILENAME_COMPONENT(test_name ${test_source} NAME_WE) diff --git a/host/tests/eeprom_c_test.c b/host/tests/eeprom_c_test.c new file mode 100644 index 000000000..0f03295e8 --- /dev/null +++ b/host/tests/eeprom_c_test.c @@ -0,0 +1,155 @@ +// +// 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 . +// + +#include + +#include +#include +#include + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_mboard_eeprom_handle mb_eeprom; + uhd_dboard_eeprom_handle db_eeprom; + int db_revision; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + /* + * Motherboard EEPROM test + */ + + // Create EEPROM handle + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_mboard_eeprom_make(&mb_eeprom) + ) + + // Set a value, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_mboard_eeprom_set_value( + mb_eeprom, + "serial", + "F12345" + ) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_mboard_eeprom_get_value( + mb_eeprom, + "serial", + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "F12345")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched EEPROM value: \"%s\" vs. \"F12345\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_mboard_eeprom; + } + + /* + * Daughterboard EEPROM test + */ + + // Create EEPROM handle + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_dboard_eeprom_make(&db_eeprom) + ) + + // Set the ID, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_id(db_eeprom, "0x0067") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_id( + db_eeprom, + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "0x0067")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard ID: \"%s\" vs. \"0x0067\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_dboard_eeprom; + } + + // Set the serial, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_serial(db_eeprom, "F12345") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_serial( + db_eeprom, + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "F12345")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard serial: \"%s\" vs. \"F12345\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_dboard_eeprom; + } + + // Set the revision, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_revision(db_eeprom, 4) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_revision(db_eeprom, &db_revision) + ) + if(db_revision != 4){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard revision: \"%d\" vs. 4\n", + __FILE__, __LINE__, db_revision); + goto free_dboard_eeprom; + } + + free_dboard_eeprom: + if(return_code){ + uhd_dboard_eeprom_last_error(db_eeprom, str_buffer, BUFFER_SIZE); + fprintf(stderr, "db_eeprom error: %s\n", str_buffer); + } + + free_mboard_eeprom: + if(return_code){ + uhd_mboard_eeprom_last_error(mb_eeprom, str_buffer, BUFFER_SIZE); + fprintf(stderr, "mb_eeprom error: %s\n", str_buffer); + } + + end_of_test: + if(!return_code){ + printf("\nNo errors detected\n"); + } + return return_code; +} diff --git a/host/tests/error_c_test.cpp b/host/tests/error_c_test.cpp new file mode 100644 index 000000000..bb9454678 --- /dev/null +++ b/host/tests/error_c_test.cpp @@ -0,0 +1,142 @@ +// +// 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 . +// + +#include +#include + +#include +#include +#include +#include + +/* + * Test our conversions from exceptions to C-level UHD error codes. + * We use inline functions separate from the Boost test cases themselves + * to test our C++ macro, which returns the error code. + */ + +typedef struct { + std::string last_error; +} dummy_handle_t; + +template +UHD_INLINE uhd_error throw_uhd_exception(dummy_handle_t *handle, const uhd::exception* except){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw *dynamic_cast(except); + ) +} + +UHD_INLINE uhd_error throw_boost_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + std::runtime_error except("This is a std::runtime_error, thrown by Boost."); + BOOST_THROW_EXCEPTION(except); + ) +} + +UHD_INLINE uhd_error throw_std_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw std::runtime_error("This is a std::runtime_error."); + ) +} + +UHD_INLINE uhd_error throw_unknown_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw 1; + ) +} + +// There are enough non-standard names that we can't just use a conversion function +static const uhd::dict pretty_exception_names = + boost::assign::map_list_of + ("assertion_error", "AssertionError") + ("lookup_error", "LookupError") + ("index_error", "LookupError: IndexError") + ("key_error", "LookupError: KeyError") + ("type_error", "TypeError") + ("value_error", "ValueError") + ("runtime_error", "RuntimeError") + ("not_implemented_error", "RuntimeError: NotImplementedError") + ("usb_error", "RuntimeError: USBError 1") + ("environment_error", "EnvironmentError") + ("io_error", "EnvironmentError: IOError") + ("os_error", "EnvironmentError: OSError") + ("system_error", "SystemError") + ; + +#define UHD_TEST_CHECK_ERROR_CODE(cpp_exception_type, c_error_code) \ + expected_msg = str(boost::format("This is a uhd::%s.") % BOOST_STRINGIZE(cpp_exception_type)); \ + uhd::cpp_exception_type cpp_exception_type ## _foo(expected_msg); \ + error_code = throw_uhd_exception(&handle, &cpp_exception_type ## _foo); \ + BOOST_CHECK_EQUAL(error_code, c_error_code); \ + BOOST_CHECK_EQUAL(handle.last_error, \ + str(boost::format("%s: %s") \ + % pretty_exception_names.get(BOOST_STRINGIZE(cpp_exception_type)) \ + % expected_msg)); + +// uhd::usb_error has a different constructor +#define UHD_TEST_CHECK_USB_ERROR_CODE() \ + expected_msg = "This is a uhd::usb_error."; \ + uhd::usb_error usb_error_foo(1, expected_msg); \ + error_code = throw_uhd_exception(&handle, &usb_error_foo); \ + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_USB); \ + BOOST_CHECK_EQUAL(handle.last_error, \ + str(boost::format("%s: %s") \ + % pretty_exception_names.get("usb_error") \ + % expected_msg)); + +BOOST_AUTO_TEST_CASE(test_uhd_exception){ + dummy_handle_t handle; + std::string expected_msg; + uhd_error error_code; + + UHD_TEST_CHECK_ERROR_CODE(assertion_error, UHD_ERROR_ASSERTION); + UHD_TEST_CHECK_ERROR_CODE(lookup_error, UHD_ERROR_LOOKUP); + UHD_TEST_CHECK_ERROR_CODE(index_error, UHD_ERROR_INDEX); + UHD_TEST_CHECK_ERROR_CODE(key_error, UHD_ERROR_KEY); + UHD_TEST_CHECK_ERROR_CODE(type_error, UHD_ERROR_TYPE); + UHD_TEST_CHECK_ERROR_CODE(value_error, UHD_ERROR_VALUE); + UHD_TEST_CHECK_ERROR_CODE(runtime_error, UHD_ERROR_RUNTIME); + UHD_TEST_CHECK_ERROR_CODE(not_implemented_error, UHD_ERROR_NOT_IMPLEMENTED); + UHD_TEST_CHECK_ERROR_CODE(io_error, UHD_ERROR_IO); + UHD_TEST_CHECK_ERROR_CODE(os_error, UHD_ERROR_OS); + UHD_TEST_CHECK_ERROR_CODE(system_error, UHD_ERROR_SYSTEM); + UHD_TEST_CHECK_USB_ERROR_CODE(); +} + +BOOST_AUTO_TEST_CASE(test_boost_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_boost_exception(&handle); + + // Boost error message cannot be determined here, so just check code + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_BOOSTEXCEPT); +} + +BOOST_AUTO_TEST_CASE(test_std_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_std_exception(&handle); + + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_STDEXCEPT); + BOOST_CHECK_EQUAL(handle.last_error, "This is a std::runtime_error."); +} + +BOOST_AUTO_TEST_CASE(test_unknown_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_unknown_exception(&handle); + + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_UNKNOWN); + BOOST_CHECK_EQUAL(handle.last_error, "Unrecognized exception caught."); +} diff --git a/host/tests/ranges_c_test.c b/host/tests/ranges_c_test.c new file mode 100644 index 000000000..da9c86a48 --- /dev/null +++ b/host/tests/ranges_c_test.c @@ -0,0 +1,236 @@ +// +// 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 . +// + +#include + +#include +#include +#include + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define UHD_TEST_CHECK_CLOSE(lhs, rhs) (fabs(lhs-rhs) < 0.001) + +#define BUFFER_SIZE 1024 + +static UHD_INLINE int test_range_values( + const uhd_range_t *range, + double start_input, double stop_input, double step_input +){ + if(!UHD_TEST_CHECK_CLOSE(range->start, start_input)){ + fprintf(stderr, "%s:%d: Starts did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->start, start_input); + return 1; + } + if(!UHD_TEST_CHECK_CLOSE(range->stop, stop_input)){ + fprintf(stderr, "%s:%d: Stops did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->stop, stop_input); + return 1; + } + if(!UHD_TEST_CHECK_CLOSE(range->step, step_input)){ + fprintf(stderr, "%s:%d: Steps did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->step, step_input); + return 1; + } + + return 0; +} + +static UHD_INLINE int test_meta_range_values( + uhd_meta_range_handle meta_range, + double start_input, double stop_input, double step_input, + double start_test, double stop_test, double step_test +){ + // Add range + uhd_range_t range; + range.start = start_input; + range.stop = stop_input; + range.step = step_input; + if(uhd_meta_range_push_back(meta_range, &range)){ + fprintf(stderr, "%s:%d: Failed to push back range.\n", + __FILE__, __LINE__); + return 1; + } + + // Test bounds + uhd_meta_range_start(meta_range, &range.start); + if(!UHD_TEST_CHECK_CLOSE(range.start, start_test)){ + fprintf(stderr, "%s:%d: Starts did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.start, start_test); + return 1; + } + uhd_meta_range_stop(meta_range, &range.stop); + if(!UHD_TEST_CHECK_CLOSE(range.stop, stop_test)){ + fprintf(stderr, "%s:%d: Stops did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.stop, stop_test); + return 1; + } + uhd_meta_range_step(meta_range, &range.step); + if(!UHD_TEST_CHECK_CLOSE(range.step, step_test)){ + fprintf(stderr, "%s:%d: Steps did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.step, step_test); + return 1; + } + + return 0; +} + +static UHD_INLINE int test_meta_range_clip( + uhd_meta_range_handle meta_range, + double clip_value, double test_value, + bool clip_step +){ + double clip_result; + + uhd_meta_range_clip(meta_range, clip_value, clip_step, &clip_result); + if(!UHD_TEST_CHECK_CLOSE(test_value, clip_result)){ + fprintf(stderr, "%s:%d: Values did not match: %f vs. %f\n", + __FILE__, __LINE__, + test_value, clip_result); + return 1; + } + + return 0; +} + +int main(){ + + // Variables + int return_code; + uhd_range_t range; + uhd_meta_range_handle meta_range1, meta_range2; + char str_buffer[BUFFER_SIZE]; + size_t size; + + return_code = EXIT_SUCCESS; + + // Create meta range 1 + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_meta_range_make(&meta_range1) + ) + + // Test bounds + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_values(meta_range1, -1.0, +1.0, 0.1, + -1.0, +1.0, 0.1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_values(meta_range1, 40.0, 60.0, 1.0, + -1.0, 60.0, 0.1) + ) + uhd_meta_range_at(meta_range1, 0, &range); + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_range_values(&range, -1.0, +1.0, 0.1) + ) + + // Check meta range size + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + uhd_meta_range_size(meta_range1, &size) + ) + if(size != 2){ + fprintf(stderr, "%s:%d: Invalid size: %lu vs. 2", + __FILE__, __LINE__, + size); + goto free_meta_range1; + } + + // Test clipping (with steps) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, -30.0, -1.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 70.0, 60.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 20.0, 1.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.0, 50.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.9, 50.9, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.9, 51.0, true) + ) + + // Create meta range 2 + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + uhd_meta_range_make(&meta_range2) + ) + range.step = 0.0; + range.start = range.stop = 1.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + range.start = range.stop = 2.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + range.start = range.stop = 3.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + + // Test clipping (without steps) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 2., 2., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 0., 1., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 1.2, 1., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 3.1, 3., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 4., 3., true) + ) + + free_meta_range2: + if(return_code){ + uhd_meta_range_last_error(meta_range2, str_buffer, BUFFER_SIZE); + fprintf(stderr, "meta_range2 error: %s\n", str_buffer); + } + uhd_meta_range_free(&meta_range1); + + free_meta_range1: + if(return_code){ + uhd_meta_range_last_error(meta_range1, str_buffer, BUFFER_SIZE); + fprintf(stderr, "meta_range1 error: %s\n", str_buffer); + } + uhd_meta_range_free(&meta_range1); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} diff --git a/host/tests/sensors_c_test.c b/host/tests/sensors_c_test.c new file mode 100644 index 000000000..8babe905a --- /dev/null +++ b/host/tests/sensors_c_test.c @@ -0,0 +1,411 @@ +// +// 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 . +// + +#include + +#include +#include +#include +#include + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define UHD_TEST_CHECK_CLOSE(lhs, rhs) (fabs(lhs-rhs) < 0.001) + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_sensor_value_handle boolean_sensor, integer_sensor, realnum_sensor, string_sensor; + uhd_sensor_value_data_type_t sensor_type; + bool bool_out; + int int_out; + double realnum_out; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + /* + * Test a sensor made from a boolean + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_sensor_value_make_from_bool( + &boolean_sensor, + "Bool sensor", false, + "True", "False" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_name( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Bool sensor")){ + fprintf(stderr, "%s:%d: Boolean sensor name invalid: \"%s\" vs. \"false\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_value( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "false")){ + fprintf(stderr, "%s:%d: Boolean sensor value invalid: \"%s\" vs. \"false\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_unit( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "False")){ + fprintf(stderr, "%s:%d: Boolean sensor unit invalid: \"%s\" vs. \"False\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_data_type( + boolean_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_BOOLEAN){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_BOOLEAN); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_to_bool( + boolean_sensor, + &bool_out + ) + ) + if(bool_out){ + fprintf(stderr, "%s:%d: Boolean sensor value invalid: true vs. false\n", + __FILE__, __LINE__); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + /* + * Test a sensor made from a integer + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_make_from_int( + &integer_sensor, + "Int sensor", 50, + "Int type", "%d" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_name( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Int sensor")){ + fprintf(stderr, "%s:%d: Integer sensor name invalid: \"%s\" vs. \"Int sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_value( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "50")){ + fprintf(stderr, "%s:%d: Integer sensor value invalid: \"%s\" vs. \"50\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_unit( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Int type")){ + fprintf(stderr, "%s:%d: Integer sensor unit invalid: \"%s\" vs. \"Int type\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_data_type( + integer_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_INTEGER){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_INTEGER); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_to_int( + integer_sensor, + &int_out + ) + ) + if(int_out != 50){ + fprintf(stderr, "%s:%d: Integer sensor value invalid: %d vs. 50\n", + __FILE__, __LINE__, + int_out); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + /* + * Test a sensor made from a real number + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_make_from_realnum( + &realnum_sensor, + "Realnum sensor", 50.0, + "Realnum type", "%d" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_name( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Realnum sensor")){ + fprintf(stderr, "%s:%d: Realnum sensor name invalid: \"%s\" vs. \"Realnum sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_value( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "50")){ + fprintf(stderr, "%s:%d: Realnum sensor value invalid: \"%s\" vs. \"50\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_unit( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Realnum type")){ + fprintf(stderr, "%s:%d: Realnum sensor unit invalid: \"%s\" vs. \"Realnum type\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_data_type( + realnum_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_REALNUM){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_REALNUM); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_to_realnum( + realnum_sensor, + &realnum_out + ) + ) + if(realnum_out != 50.0){ + fprintf(stderr, "%s:%d: Realnum sensor value invalid: %2.1f vs. 50.0\n", + __FILE__, __LINE__, + realnum_out); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + /* + * Test a sensor made from a string + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_make_from_string( + &string_sensor, + "String sensor", + "String value", + "String unit" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_name( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String sensor")){ + fprintf(stderr, "%s:%d: String sensor name invalid: \"%s\" vs. \"String sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_value( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String value")){ + fprintf(stderr, "%s:%d: String sensor value invalid: \"%s\" vs. \"String value\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_unit( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String unit")){ + fprintf(stderr, "%s:%d: String sensor unit invalid: \"%s\" vs. \"String unit\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_data_type( + string_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_STRING){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_STRING); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + /* + * Cleanup + */ + + free_string_sensor: + if(return_code){ + uhd_sensor_value_last_error(string_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "string_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&string_sensor); + + free_realnum_sensor: + if(return_code){ + uhd_sensor_value_last_error(realnum_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "realnum_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&realnum_sensor); + + free_integer_sensor: + if(return_code){ + uhd_sensor_value_last_error(integer_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "integer_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&integer_sensor); + + free_boolean_sensor: + if(return_code){ + uhd_sensor_value_last_error(boolean_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "boolean_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&boolean_sensor); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} diff --git a/host/tests/subdev_spec_c_test.c b/host/tests/subdev_spec_c_test.c new file mode 100644 index 000000000..7663ba357 --- /dev/null +++ b/host/tests/subdev_spec_c_test.c @@ -0,0 +1,130 @@ +// +// 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 . +// + +#include + +#include +#include + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_subdev_spec_pair_t subdev_spec_pair1, subdev_spec_pair2; + uhd_subdev_spec_handle subdev_spec1, subdev_spec2; + size_t size1, size2, i; + bool pairs_equal; + char str_buffer[BUFFER_SIZE]; + + printf("Testing subdevice specification...\n"); + return_code = EXIT_SUCCESS; + + // Create subdev spec + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_subdev_spec_make(&subdev_spec1, "A:AB B:AB") + ) + + // Convert to and from args string + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec1, + uhd_subdev_spec_to_pp_string(subdev_spec1, str_buffer, BUFFER_SIZE) + ) + printf("Pretty Print:\n%s", str_buffer); + + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec1, + uhd_subdev_spec_to_string(subdev_spec1, str_buffer, BUFFER_SIZE) + ) + printf("Markup String: %s\n", str_buffer); + + // Make a second subdev spec from the first's markup string + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_make(&subdev_spec2, str_buffer) + ) + + // Make sure both subdev specs are equal + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_size(subdev_spec1, &size1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_size(subdev_spec2, &size2) + ) + if(size1 != size2){ + printf("%s:%d: Sizes do not match. %lu vs. %lu\n", __FILE__, __LINE__, size1, size2); + return_code = EXIT_FAILURE; + goto free_subdev_spec2; + } + for(i = 0; i < size1; i++){ + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair1, + uhd_subdev_spec_at(subdev_spec1, i, &subdev_spec_pair1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair2, + uhd_subdev_spec_at(subdev_spec2, i, &subdev_spec_pair2) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair2, + uhd_subdev_spec_pairs_equal(&subdev_spec_pair1, &subdev_spec_pair2, &pairs_equal) + ) + if(!pairs_equal){ + printf("%s:%d: Subdev spec pairs are not equal.\n" + " db_name: %s vs. %s\n" + " sd_name: %s vs. %s\n", + __FILE__, __LINE__, + subdev_spec_pair1.db_name, subdev_spec_pair2.db_name, + subdev_spec_pair1.sd_name, subdev_spec_pair2.sd_name + ); + return_code = EXIT_FAILURE; + goto free_subdev_spec_pair2; + } + uhd_subdev_spec_pair_free(&subdev_spec_pair1); + uhd_subdev_spec_pair_free(&subdev_spec_pair2); + } + + // Cleanup (and error report, if needed) + + free_subdev_spec_pair2: + uhd_subdev_spec_pair_free(&subdev_spec_pair2); + + free_subdev_spec_pair1: + uhd_subdev_spec_pair_free(&subdev_spec_pair1); + + free_subdev_spec2: + if(return_code){ + uhd_subdev_spec_last_error(subdev_spec2, str_buffer, BUFFER_SIZE); + fprintf(stderr, "subdev_spec2 error: %s\n", str_buffer); + } + uhd_subdev_spec_free(&subdev_spec2); + + free_subdev_spec1: + if(return_code){ + uhd_subdev_spec_last_error(subdev_spec1, str_buffer, BUFFER_SIZE); + fprintf(stderr, "subdev_spec1 error: %s\n", str_buffer); + } + uhd_subdev_spec_free(&subdev_spec1); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} -- cgit v1.2.3 From f4e7debd1fea196e37f921bf1b3025fcfc6816b5 Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Thu, 6 Aug 2015 15:16:54 -0500 Subject: libusb: Fixed Windows build issue - Introduced in b08352f267730ea417ec345cd90833a6746a1114. ERROR is a macro included through some windows specific header. Replaced with STATUS_ERROR. --- host/lib/transport/libusb1_zero_copy.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index fe0eb9bfd..7b191edaf 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -222,7 +222,7 @@ public: _frame_size(frame_size), _buffer_pool(buffer_pool::make(_num_frames, _frame_size)), _enqueued(_num_frames), _released(_num_frames), - _status(RUNNING) + _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)); @@ -308,7 +308,7 @@ public: { typename buffer_type::sptr buff; - if (_status == ERROR) + if (_status == STATUS_ERROR) return buff; // Serialize access to buffers @@ -349,7 +349,7 @@ private: //! why 2 queues? there is room in the future to have > N buffers but only N in flight boost::circular_buffer _enqueued, _released; - enum {RUNNING,ERROR} _status; + enum {STATUS_RUNNING, STATUS_ERROR} _status; void enqueue_buffer(libusb_zero_copy_mb *mb) { @@ -361,7 +361,7 @@ private: void submit_what_we_can(void) { - if (_status == ERROR) + if (_status == STATUS_ERROR) return; while (not _released.empty() and not _enqueued.full()) { @@ -372,7 +372,7 @@ private: } catch (uhd::runtime_error& e) { - _status = ERROR; + _status = STATUS_ERROR; throw e; } } -- cgit v1.2.3 From 0f2346554d47678cb924f94ce7d6cd7bc94238ef Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 6 Aug 2015 16:01:13 -0700 Subject: UHD: libusb_strerror compatibility with older versions of libusb --- host/cmake/Modules/FindUSB1.cmake | 7 ++++++- host/lib/transport/libusb1_base.hpp | 23 +++++++++++++++++++++++ host/lib/transport/libusb1_zero_copy.cpp | 17 ----------------- 3 files changed, 29 insertions(+), 18 deletions(-) (limited to 'host/lib') diff --git a/host/cmake/Modules/FindUSB1.cmake b/host/cmake/Modules/FindUSB1.cmake index 1e8e3ba03..7c4a8fb6b 100644 --- a/host/cmake/Modules/FindUSB1.cmake +++ b/host/cmake/Modules/FindUSB1.cmake @@ -8,7 +8,7 @@ PKG_CHECK_MODULES(PC_LIBUSB QUIET libusb-1.0) FIND_PATH(LIBUSB_INCLUDE_DIRS NAMES libusb.h - HINTS $ENV{LIBUSB_DIR}/include $ENV{LIBUSB_DIR}/include/libusb-1.0 + HINTS $ENV{LIBUSB_DIR}/include $ENV{LIBUSB_DIR}/include/libusb-1.0 ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDEDIR}/libusb-1.0 PATHS /usr/local/include/libusb-1.0 /usr/local/include /usr/include/libusb-1.0 /usr/include @@ -52,6 +52,11 @@ if(HAVE_LIBUSB_ERROR_NAME) list(APPEND LIBUSB_DEFINITIONS "HAVE_LIBUSB_ERROR_NAME=1") endif(HAVE_LIBUSB_ERROR_NAME) +CHECK_FUNCTION_EXISTS("libusb_strerror" HAVE_LIBUSB_STRERROR) +if(HAVE_LIBUSB_STRERROR) + list(APPEND LIBUSB_DEFINITIONS "HAVE_LIBUSB_STRERROR=1") +endif(HAVE_LIBUSB_STRERROR) + include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIRS) MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES) diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 2e16dc176..2ff1291d9 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -24,6 +24,29 @@ #include #include +//! 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 diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 7b191edaf..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 > mb_queue_sptr; -- cgit v1.2.3 From c2cf9c30f6b5091ba6ab4c5cad26e2ef649595af Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 6 Aug 2015 18:07:12 -0700 Subject: e300: Fix lacking subscriber call to update LO freq and bandsels --- host/lib/usrp/e300/e300_impl.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'host/lib') diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 6eb63c786..45c00ffbb 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -1074,6 +1074,9 @@ void e300_impl::_setup_radio(const size_t dspno) _tree->create(rf_fe_path / "sensors" / "lo_locked") .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, dir == TX_DIRECTION)) ; + _tree->access(rf_fe_path / "freq" / "value") + .subscribe(boost::bind(&e300_impl::_update_fe_lo_freq, this, key, _1)) + ; // Network mode currently doesn't support the filter API, so // prevent it from using it: -- cgit v1.2.3 From 3a7420fc4ffc246616e53259a3c8d718f9fa7c54 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 6 Aug 2015 13:51:27 -0700 Subject: e300: Made network mode not crash when attempting to user filter API --- host/lib/usrp/e300/e300_impl.cpp | 6 ------ host/lib/usrp/e300/e300_remote_codec_ctrl.cpp | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 45c00ffbb..e3c2e19c1 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -1078,12 +1078,6 @@ void e300_impl::_setup_radio(const size_t dspno) .subscribe(boost::bind(&e300_impl::_update_fe_lo_freq, this, key, _1)) ; - // 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"); - } - // Antenna Setup if (dir == RX_DIRECTION) { static const std::vector ants = boost::assign::list_of("TX/RX")("RX2"); 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 get_filter_names(const std::string &) { - UHD_THROW_INVALID_CODE_PATH(); + return std::vector(); } //! 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: -- cgit v1.2.3 From c2827e9a0bcfe9c2dd2e4dd5d68f895384564ec6 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 30 Jul 2015 12:40:24 -0700 Subject: x300, e300: Moved common register names to radio namespace This preps the code for merging common registers altogether. --- host/lib/usrp/e300/e300_impl.cpp | 30 +++++++-------- host/lib/usrp/e300/e300_regs.hpp | 62 ++++++++++++++++++------------ host/lib/usrp/x300/x300_adc_dac_utils.cpp | 6 +-- host/lib/usrp/x300/x300_impl.cpp | 30 +++++++-------- host/lib/usrp/x300/x300_impl.hpp | 4 +- host/lib/usrp/x300/x300_regs.hpp | 63 +++++++++++++++++-------------- 6 files changed, 107 insertions(+), 88 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index e3c2e19c1..06f8e9e58 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::GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create(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 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 +#include +#include -#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/x300/x300_adc_dac_utils.cpp b/host/lib/usrp/x300/x300_adc_dac_utils.cpp index 2dadea26e..efc2c8ed1 100644 --- a/host/lib/usrp/x300/x300_adc_dac_utils.cpp +++ b/host/lib/usrp/x300/x300_adc_dac_utils.cpp @@ -39,7 +39,7 @@ void x300_impl::synchronize_dacs(const std::vector& 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; @@ -54,7 +54,7 @@ void x300_impl::synchronize_dacs(const std::vector& 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 } @@ -71,7 +71,7 @@ void x300_impl::synchronize_dacs(const std::vector& 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_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index c9cc0cabc..3a50f7ea0 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -745,7 +745,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(mb_path / "gpio" / "FP0" / attr.second) @@ -934,30 +934,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" @@ -1021,7 +1021,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; @@ -1334,8 +1334,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_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 20cd4d754..3cec7d5ce 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -182,7 +182,7 @@ private: 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] - radio_misc_outs_reg(): uhd::soft_reg32_wo_t(TOREG(SR_MISC_OUTS)) { + radio_misc_outs_reg(): 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); @@ -203,7 +203,7 @@ private: 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] - radio_misc_ins_reg(): uhd::soft_reg32_ro_t(RB32_MISC_INS) { } + radio_misc_ins_reg(): uhd::soft_reg32_ro_t(uhd::usrp::radio::RB32_MISC_INS) { } }; //perifs in the radio core diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 6e92a6dbc..ac2fcc31e 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -18,39 +18,46 @@ #ifndef INCLUDED_X300_REGS_HPP #define INCLUDED_X300_REGS_HPP +#include #include -#include -#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; -- cgit v1.2.3 From f1ebf688291a8f3026940125b2af50e069272fd8 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Fri, 7 Aug 2015 10:25:27 -0700 Subject: C API: feature additions, bugfixes * Wrapped uhd::device_addrs_t, added find functions for multi_usrp, multi_usrp_clock * Replaced getopt with public domain implementation * Minor bugfixes --- host/docs/CMakeLists.txt | 4 +- host/examples/getopt/CMakeLists.txt | 1 - host/examples/getopt/getopt.c | 1098 ++---------------------------- host/examples/getopt/getopt.h | 199 +----- host/examples/getopt/getopt1.c | 188 ----- host/examples/rx_samples_c.c | 8 +- host/examples/tx_samples_c.c | 10 +- host/include/uhd.h | 1 + host/include/uhd/types/CMakeLists.txt | 1 + host/include/uhd/types/device_addrs.h | 87 +++ host/include/uhd/usrp/usrp.h | 11 + host/include/uhd/usrp_clock/usrp_clock.h | 19 +- host/lib/types/CMakeLists.txt | 1 + host/lib/types/device_addrs_c.cpp | 78 +++ host/lib/usrp/usrp_c.cpp | 14 + host/lib/usrp_clock/usrp_clock_c.cpp | 14 + host/tests/CMakeLists.txt | 1 + host/tests/device_addrs_c_test.c | 90 +++ host/tests/eeprom_c_test.c | 2 + 19 files changed, 402 insertions(+), 1425 deletions(-) delete mode 100644 host/examples/getopt/getopt1.c create mode 100644 host/include/uhd/types/device_addrs.h create mode 100644 host/lib/types/device_addrs_c.cpp create mode 100644 host/tests/device_addrs_c_test.c (limited to 'host/lib') diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 3ad2ef37c..063bfd901 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -74,7 +74,9 @@ ENDIF(LIBUHDDEV_PKG) IF(ENABLE_DOXYGEN) SET(ENABLE_MANUAL_OR_DOXYGEN true) #make doxygen directory depend on the header files - FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.h*) + FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp) + FILE(GLOB_RECURSE h_files ${CMAKE_SOURCE_DIR}/include/*.h) + LIST(APPEND header_files ${h_files}) SET(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files}) IF(ENABLE_DOXYGEN_FULL) SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib") diff --git a/host/examples/getopt/CMakeLists.txt b/host/examples/getopt/CMakeLists.txt index 2321a0d94..46ad1460c 100644 --- a/host/examples/getopt/CMakeLists.txt +++ b/host/examples/getopt/CMakeLists.txt @@ -21,5 +21,4 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIRECTORY}) ADD_LIBRARY(getopt STATIC ${CMAKE_CURRENT_SOURCE_DIR}/getopt.c - ${CMAKE_CURRENT_SOURCE_DIR}/getopt1.c ) diff --git a/host/examples/getopt/getopt.c b/host/examples/getopt/getopt.c index ad9ec2f9b..e571ff9c8 100644 --- a/host/examples/getopt/getopt.c +++ b/host/examples/getopt/getopt.c @@ -1,1056 +1,70 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to drepper@gnu.org - before changing it! - Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif +/* + * This file was copied from the following newsgroup posting: + * + * Newsgroups: mod.std.unix + * Subject: public domain AT&T getopt source + * Date: 3 Nov 85 19:34:15 GMT + * + * Here's something you've all been waiting for: the AT&T public domain + * source for getopt(3). It is the code which was given out at the 1985 + * UNIFORUM conference in Dallas. I obtained it by electronic mail + * directly from AT&T. The people there assure me that it is indeed + * in the public domain. + */ #include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ - -#ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. */ -# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC -# include -# ifndef _ -# define _(msgid) gettext (msgid) -# endif -# else -# define _(msgid) (msgid) -# endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -# include -# define my_index strchr -#else - #include -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -#ifndef getenv -#ifdef _MSC_VER -// DDK will complain if you don't use the stdlib defined getenv -#include -#else -extern char *getenv (); -#endif -#endif - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Stored original parameters. - XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ -extern int __libc_argc; -extern char **__libc_argv; - -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -# ifdef USE_NONOPTION_FLAGS -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; -# endif - -# ifdef USE_NONOPTION_FLAGS -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -# else -# define SWAP_FLAGS(ch1, ch2) -# endif -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ +#define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);} -#if defined __STDC__ && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - -#if defined _LIBC && defined USE_NONOPTION_FLAGS - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#if defined _LIBC && defined USE_NONOPTION_FLAGS - if (posixly_correct == NULL - && argc == __libc_argc && argv == __libc_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; +getopt(int argc, char **argv, char *opts) { - int print_errors = opterr; - if (optstring[0] == ':') - print_errors = 0; - - if (argc < 1) - return -1; - - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; + static int sp; + int c; + char *cp; + + sp = 1; + + if (sp == 1) { + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return (EOF); + else if (strcmp(argv[optind], "--") == 0) { + optind++; + return (EOF); } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#if defined _LIBC && defined USE_NONOPTION_FLAGS -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (print_errors) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - } - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (print_errors) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } + optopt = c = argv[optind][sp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + ERR(": illegal option -- ", c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (print_errors) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p != NULL && p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (print_errors) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } + return ('?'); } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); + if (*++cp == ':') { + if (argv[optind][sp + 1] != '\0') + optarg = &argv[optind++][sp + 1]; + else if (++optind >= argc) { + ERR(": option requires an argument -- ", c); + sp = 1; + return ('?'); + } else + optarg = argv[optind++]; + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; } - - exit (0); + optarg = NULL; + } + return (c); } - -#endif /* TEST */ diff --git a/host/examples/getopt/getopt.h b/host/examples/getopt/getopt.h index a1b8dd665..ada96ecf0 100644 --- a/host/examples/getopt/getopt.h +++ b/host/examples/getopt/getopt.h @@ -1,180 +1,19 @@ -/* Declarations for getopt. - Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _GETOPT_H - -#ifndef __need_getopt -# define _GETOPT_H 1 -#endif - -/* If __GNU_LIBRARY__ is not already defined, either we are being used - standalone, or this is the first header included in the source file. - If we are being used with glibc, we need to include , but - that does not exist if we are standalone. So: if __GNU_LIBRARY__ is - not defined, include , which will pull in for us - if it's from glibc. (Why ctype.h? It's guaranteed to exist and it - doesn't flood the namespace with stuff the way some other headers do.) */ -#if !defined __GNU_LIBRARY__ -# include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -#ifndef __need_getopt -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -# if (defined __STDC__ && __STDC__) || defined __cplusplus - const char *name; -# else - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#if (defined __STDC__ && __STDC__) || defined __cplusplus -# ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int __argc, char *const *__argv, const char *__shortopts); -# else /* not __GNU_LIBRARY__ */ -extern int getopt (); -# endif /* __GNU_LIBRARY__ */ - -# ifndef __need_getopt -extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ -extern int getopt (); -# ifndef __need_getopt -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt - -#endif /* getopt.h */ +/* + * This header is for a function released into the public domain + * by AT&T in 1985. See the newsgroup posting: + * + * Newsgroups: mod.std.unix + * Subject: public domain AT&T getopt source + * Date: 3 Nov 85 19:34:15 GMT + */ +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +extern int optarr; +extern int optind; +extern int optopt; +extern char* optarg; + +int getopt(int argc, char **argv, char *opts); + +#endif /* _GETOPT_H_ */ diff --git a/host/examples/getopt/getopt1.c b/host/examples/getopt/getopt1.c deleted file mode 100644 index 22a7efbdd..000000000 --- a/host/examples/getopt/getopt1.c +++ /dev/null @@ -1,188 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "getopt.h" - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/host/examples/rx_samples_c.c b/host/examples/rx_samples_c.c index 0be0d8afe..b5882b79b 100644 --- a/host/examples/rx_samples_c.c +++ b/host/examples/rx_samples_c.c @@ -108,19 +108,19 @@ int main(int argc, char* argv[]) // Create USRP uhd_usrp_handle usrp; fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); - EXECUTE_OR_GOTO(free_usrp, + EXECUTE_OR_GOTO(free_option_strings, uhd_usrp_make(&usrp, device_args) ) // Create RX streamer uhd_rx_streamer_handle rx_streamer; - EXECUTE_OR_GOTO(free_rx_streamer, + EXECUTE_OR_GOTO(free_usrp, uhd_rx_streamer_make(&rx_streamer) ) // Create RX metadata uhd_rx_metadata_handle md; - EXECUTE_OR_GOTO(free_rx_metadata, + EXECUTE_OR_GOTO(free_rx_streamer, uhd_rx_metadata_make(&md) ) @@ -272,7 +272,7 @@ int main(int argc, char* argv[]) if(verbose){ fprintf(stderr, "Cleaning up USRP.\n"); } - if(return_code != EXIT_SUCCESS){ + if(return_code != EXIT_SUCCESS && usrp != NULL){ uhd_usrp_last_error(usrp, error_string, 512); fprintf(stderr, "USRP reported the following error: %s\n", error_string); } diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c index 5a4b79005..3035297fd 100644 --- a/host/examples/tx_samples_c.c +++ b/host/examples/tx_samples_c.c @@ -102,19 +102,19 @@ int main(int argc, char* argv[]){ // Create USRP uhd_usrp_handle usrp; fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); - EXECUTE_OR_GOTO(free_usrp, + EXECUTE_OR_GOTO(free_option_strings, uhd_usrp_make(&usrp, device_args) ) // Create TX streamer uhd_tx_streamer_handle tx_streamer; - EXECUTE_OR_GOTO(free_tx_streamer, + EXECUTE_OR_GOTO(free_usrp, uhd_tx_streamer_make(&tx_streamer) ) // Create TX metadata uhd_tx_metadata_handle md; - EXECUTE_OR_GOTO(free_tx_metadata, + EXECUTE_OR_GOTO(free_tx_streamer, uhd_tx_metadata_make(&md, false, 0.0, 0.1, true, false) ) @@ -224,7 +224,7 @@ int main(int argc, char* argv[]){ if(verbose){ fprintf(stderr, "Cleaning up USRP.\n"); } - if(return_code != EXIT_SUCCESS){ + if(return_code != EXIT_SUCCESS && usrp != NULL){ uhd_usrp_last_error(usrp, error_string, 512); fprintf(stderr, "USRP reported the following error: %s\n", error_string); } @@ -235,7 +235,7 @@ int main(int argc, char* argv[]){ free(device_args); } - fprintf(stderr, (return_code ? "Failure" : "Success")); + fprintf(stderr, (return_code ? "Failure\n" : "Success\n")); return return_code; } diff --git a/host/include/uhd.h b/host/include/uhd.h index 0ecafa88a..1f8f9e896 100644 --- a/host/include/uhd.h +++ b/host/include/uhd.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 140b5c710..07a752806 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -45,6 +45,7 @@ UHD_INSTALL(FILES IF(ENABLE_C_API) UHD_INSTALL(FILES + device_addrs.h metadata.h ranges.h sensors.h diff --git a/host/include/uhd/types/device_addrs.h b/host/include/uhd/types/device_addrs.h new file mode 100644 index 000000000..3acc7f179 --- /dev/null +++ b/host/include/uhd/types/device_addrs.h @@ -0,0 +1,87 @@ +/* + * Copyright 2015 Ettus Research + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDED_UHD_TYPES_DEVICE_ADDRS_H +#define INCLUDED_UHD_TYPES_DEVICE_ADDRS_H + +#include +#include + +#include + +#ifdef __cplusplus +#include +#include + +struct uhd_device_addrs_t { + uhd::device_addrs_t device_addrs_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_device_addrs_t; +#endif + +//! C-level interface for interacting with a list of device addresses +/*! + * See uhd::device_addrs_t for more information. + */ +typedef struct uhd_device_addrs_t* uhd_device_addrs_handle; + +//! Instantiate a device_addrs handle. +UHD_API uhd_error uhd_device_addrs_make( + uhd_device_addrs_handle *h +); + +//! Safely destroy a device_addrs handle. +UHD_API uhd_error uhd_device_addrs_free( + uhd_device_addrs_handle *h +); + +//! Add a device address to the list in string form +UHD_API uhd_error uhd_device_addrs_push_back( + uhd_device_addrs_handle h, + const char* value +); + +//! Get the device information (in string form) at the given index +UHD_API uhd_error uhd_device_addrs_at( + uhd_device_addrs_handle h, + size_t index, + char* value_out, + size_t strbuffer_len +); + +//! Get the number of device addresses in this list +UHD_API uhd_error uhd_device_addrs_size( + uhd_device_addrs_handle h, + size_t *size_out +); + +//! Get the last error reported by the underlying object +UHD_API uhd_error uhd_device_addrs_last_error( + uhd_device_addrs_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_DEVICE_ADDRS_H */ diff --git a/host/include/uhd/usrp/usrp.h b/host/include/uhd/usrp/usrp.h index e828628c7..99a06b6e1 100644 --- a/host/include/uhd/usrp/usrp.h +++ b/host/include/uhd/usrp/usrp.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -291,6 +292,16 @@ typedef struct uhd_usrp* uhd_usrp_handle; extern "C" { #endif +//! Find all connected USRP devices. +/*! + * See uhd::device::find() for more details. + */ +UHD_API uhd_error uhd_usrp_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +); + //! Create a USRP handle. /*! * \param h the handle diff --git a/host/include/uhd/usrp_clock/usrp_clock.h b/host/include/uhd/usrp_clock/usrp_clock.h index 2f5a1db29..4a9eb871e 100644 --- a/host/include/uhd/usrp_clock/usrp_clock.h +++ b/host/include/uhd/usrp_clock/usrp_clock.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -47,8 +48,18 @@ typedef struct uhd_usrp_clock* uhd_usrp_clock_handle; extern "C" { #endif -/*! Create a USRP Clock handle. - * +//! Find all connected clock devices. +/*! + * See uhd::device::find() for more details. + */ +UHD_API uhd_error uhd_usrp_clock_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +); + +//! Create a clock handle. +/*! * \param h The handle * \param args Device args (e.g. "addr=192.168.10.3") */ @@ -57,8 +68,8 @@ UHD_API uhd_error uhd_usrp_clock_make( const char *args ); -/*! Safely destroy the USRP_CLOCK object underlying the handle. - * +//! Safely destroy the clock object underlying the handle. +/*! * Note: After calling this, usage of h may cause segmentation faults. * However, multiple calling of uhd_usrp_free() is safe. */ diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index d8938c8a8..891977065 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -97,6 +97,7 @@ LIBUHD_APPEND_SOURCES( 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 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 . +// + +#include + +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/usrp/usrp_c.cpp b/host/lib/usrp/usrp_c.cpp index 3eaf70405..829014829 100644 --- a/host/lib/usrp/usrp_c.cpp +++ b/host/lib/usrp/usrp_c.cpp @@ -249,6 +249,20 @@ uhd_error uhd_tx_streamer_last_error( /**************************************************************************** * 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, diff --git a/host/lib/usrp_clock/usrp_clock_c.cpp b/host/lib/usrp_clock/usrp_clock_c.cpp index b55abc852..dc5913534 100644 --- a/host/lib/usrp_clock/usrp_clock_c.cpp +++ b/host/lib/usrp_clock/usrp_clock_c.cpp @@ -54,6 +54,20 @@ UHD_SINGLETON_FCN(usrp_clock_ptrs, get_usrp_clock_ptrs); /**************************************************************************** * 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, diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 009509286..ac0486f2e 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -55,6 +55,7 @@ SET(UHD_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS}) IF(ENABLE_C_API) LIST(APPEND test_sources + device_addrs_c_test.c eeprom_c_test.c error_c_test.cpp ranges_c_test.c diff --git a/host/tests/device_addrs_c_test.c b/host/tests/device_addrs_c_test.c new file mode 100644 index 000000000..e84068a75 --- /dev/null +++ b/host/tests/device_addrs_c_test.c @@ -0,0 +1,90 @@ +// +// 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 . +// + +#include + +#include +#include +#include + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_device_addrs_handle device_addrs; + size_t size; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + // Create device_addrs + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_device_addrs_make(&device_addrs) + ) + + // Add values + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_push_back(device_addrs, "key1=value1,key2=value2") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_push_back(device_addrs, "key3=value3,key4=value4") + ) + + // Check size + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_size(device_addrs, &size) + ) + if(size != 2){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Invalid size: %lu vs. 2", + __FILE__, __LINE__,size); + goto free_device_addrs; + } + + // Make sure we get right value + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_at(device_addrs, 1, str_buffer, BUFFER_SIZE) + ) + if(strcmp(str_buffer, "key3=value3,key4=value4")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard serial: \"%s\" vs. \"key3=value3,key4=value4\"\n", + __FILE__, __LINE__, + str_buffer); + } + + free_device_addrs: + if(return_code){ + uhd_device_addrs_last_error(device_addrs, str_buffer, BUFFER_SIZE); + fprintf(stderr, "device_addrs error: %s\n", str_buffer); + } + uhd_device_addrs_free(&device_addrs); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected\n"); + } + return return_code; +} diff --git a/host/tests/eeprom_c_test.c b/host/tests/eeprom_c_test.c index 0f03295e8..1b29dfd44 100644 --- a/host/tests/eeprom_c_test.c +++ b/host/tests/eeprom_c_test.c @@ -140,12 +140,14 @@ int main(){ uhd_dboard_eeprom_last_error(db_eeprom, str_buffer, BUFFER_SIZE); fprintf(stderr, "db_eeprom error: %s\n", str_buffer); } + uhd_dboard_eeprom_free(&db_eeprom); free_mboard_eeprom: if(return_code){ uhd_mboard_eeprom_last_error(mb_eeprom, str_buffer, BUFFER_SIZE); fprintf(stderr, "mb_eeprom error: %s\n", str_buffer); } + uhd_mboard_eeprom_free(&mb_eeprom); end_of_test: if(!return_code){ -- cgit v1.2.3 From 8c0731276af9c82f9419ec16334ec919d0414fc0 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 10 Aug 2015 10:55:00 -0700 Subject: ad936x: Disable AGC by default --- host/lib/usrp/common/ad936x_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib') 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 { -- cgit v1.2.3 From 377850c9699331a24650a8bc41142627f3ab4330 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Mon, 10 Aug 2015 10:25:15 -0700 Subject: e300: added -DE300_FORCE_NETWORK flag to CMake configuration * Fixes building E300 support in native mode on any Linux system with libudev headers * Added E300_NATIVE check to e300_common.cpp * Improved network mode documentation --- host/docs/usrp_e3x0.dox | 16 +++++++++++++++- host/lib/usrp/e300/CMakeLists.txt | 4 ++-- host/lib/usrp/e300/e300_common.cpp | 16 ++++++++++++++++ host/utils/CMakeLists.txt | 4 ++-- 4 files changed, 35 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/docs/usrp_e3x0.dox b/host/docs/usrp_e3x0.dox index f34aef229..e6a574a51 100644 --- a/host/docs/usrp_e3x0.dox +++ b/host/docs/usrp_e3x0.dox @@ -134,6 +134,8 @@ which should return 'arm-oe-linux-gnueabi'. $ cmake -DCMAKE_TOOLCHAIN_FILE=/host/cmake/Toolchains/oe-sdk_cross.cmake -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_E300=ON .. $ make +For instructions on building UHD on a PC to interact with your E-Series device, follow these instructions: \ref e3x0_uhd_build + \subsubsection e3x0_sdk_usage_gnuradio Building GNU Radio -# Obtain the gnuradio source code via git. @@ -699,10 +701,22 @@ they can be queried through the API. \subsection e3x0_network_mode Network Mode -Your USRP-E series device can be used in network mode for narrow band signal observation, evaluation and debugging purposes. +Your USRP-E series device can be used in network mode for narrow band signal observation, evaluation and debugging purposes. See the instructions below for how to use network mode. Please note that when compared with normal operation as a standalone device the usable bandwidth is limited and therefore Network Mode is not the recommended mode of operation. +\subsubsection e3x0_uhd_build Building UHD + +To work with your E-Series device in network mode, you will need to build UHD on your PC with extra CMake flags. Assuming you are in the host/build directory, +see below: + + $ cmake -DENABLE_E300=ON -DE300_FORCE_NETWORK=ON .. + $ make + +Once UHD is installed on your device, it will be able to interact with an E-Series device with network mode active (see below). + +\subsubsection e3x0_activating_network Activating Network Mode on the Device + In order to use the device in network mode it is necessary to start the *usrp_e3x0_network_mode* executable on the device. In order to start the executable please log into your device either via SSH or serial console(see \ref e3x0_first_boot) and type 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 #include +#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/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 530bcf087..06bee48cd 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -34,11 +34,11 @@ SET(x3xx_burner_sources ) find_package(UDev) -IF(ENABLE_E300) +IF(ENABLE_E300 AND NOT E300_FORCE_NETWORK) IF(UDEV_FOUND) LIST(APPEND util_runtime_sources usrp_e3x0_network_mode.cpp) ENDIF(UDEV_FOUND) -ENDIF(ENABLE_E300) +ENDIF(ENABLE_E300 AND NOT E300_FORCE_NETWORK) #for each source: build an executable and install FOREACH(util_source ${util_runtime_sources}) -- cgit v1.2.3 From b2c847acb2c2913d3a2a73e3da863a3ee0d730e5 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Mon, 10 Aug 2015 14:54:10 -0700 Subject: x300: added missing included necessary in Boost 1.46 --- host/lib/usrp/x300/x300_impl.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'host/lib') diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 3a50f7ea0..5b202aba9 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 46342c082d851d05afae8c94421d35ea3cf881eb Mon Sep 17 00:00:00 2001 From: Tom Tsou Date: Mon, 10 Aug 2015 15:37:09 -0700 Subject: e300: Fix internal GPIO register setting Resolves issue #890 "E300: Does not transmit on master" Fixes GPIO register mismatch introduced by c2827e9a0b. "x300, e300: Moved common register names to radio namespace" With register correction, transmit and LED behaviour performs as expected. Signed-off-by: Tom Tsou --- host/lib/usrp/e300/e300_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib') diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 06f8e9e58..5bef783f6 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -512,7 +512,7 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) //////////////////////////////////////////////////////////////////// // internal gpios //////////////////////////////////////////////////////////////////// - gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::GPIO), radio::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(mb_path / "gpio" / "INT0" / attr.second) -- cgit v1.2.3