diff options
author | Josh Blum <josh@joshknows.com> | 2010-03-30 13:32:52 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-03-30 13:32:52 +0000 |
commit | f94fa1e464c9e2a87274c991dc6461f7f4c956d8 (patch) | |
tree | 1b88020a0dece1ae509cf3fb219b7cce487dc198 | |
parent | 29e88b3478aad89ff76363029395200a8601e667 (diff) | |
parent | 281307833c8275031bd2469e6aef3f472490749a (diff) | |
download | uhd-f94fa1e464c9e2a87274c991dc6461f7f4c956d8.tar.gz uhd-f94fa1e464c9e2a87274c991dc6461f7f4c956d8.tar.bz2 uhd-f94fa1e464c9e2a87274c991dc6461f7f4c956d8.zip |
Merge branch 'master' of git@ettus.sourcerepo.com:ettus/uhd into usrp_e
Conflicts:
host/include/uhd/usrp/dboard_id.hpp
host/lib/usrp/usrp2/usrp2_impl.cpp
79 files changed, 2749 insertions, 1118 deletions
diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index b82c7702b..262995885 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -22,6 +22,8 @@ #include "config.h" #endif +#define DEBUG_MODE 0 //0 for normal operation + #include <lwip/ip.h> #include <lwip/udp.h> #include "u2_init.h" @@ -50,13 +52,6 @@ #include <ethertype.h> #include <arp_cache.h> -#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) - -#if (FW_SETS_SEQNO) -static int fw_seqno; // used when f/w is filling in sequence numbers -#endif - - /* * Full duplex Tx and Rx between ethernet and DSP pipelines * @@ -102,8 +97,15 @@ dbsm_t dsp_tx_sm; // the state machine * ================================================================ */ +typedef struct{ + uint32_t control_word; + uint32_t vrt_header[]; +} rx_dsp_buff_t; + +#define MK_RX_CTRL_WORD(num_words) (((num_words)*sizeof(uint32_t)) | (1 << 16)) + // DSP Rx writes ethernet header words -#define DSP_RX_FIRST_LINE 1 //1 = control stuff to udp sm +#define DSP_RX_FIRST_LINE 1 //1 = number of control words (see above) // receive from DSP buf_cmd_args_t dsp_rx_recv_args = { @@ -125,18 +127,14 @@ dbsm_t dsp_rx_sm; // the state machine // The mac address of the host we're sending to. eth_mac_addr_t host_mac_addr; -#define TIME_NOW ((uint32_t)(~0)) - -// variables for streaming mode - -static bool streaming_p = false; -static unsigned int streaming_items_per_frame = 0; -static uint32_t time_secs = TIME_NOW; -static uint32_t time_ticks = TIME_NOW; -static int streaming_frame_count = 0; +//controls continuous streaming... +static bool auto_reload_command = false; +static size_t streaming_items_per_frame = 0; +static int streaming_frame_count = 0; #define FRAMES_PER_CMD 2 -bool is_streaming(void){ return streaming_p; } +static void setup_network(void); +static void setup_vrt(void); // ---------------------------------------------------------------- // the fast-path setup global variables @@ -157,6 +155,9 @@ void handle_udp_data_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len ){ + //store the 2nd word as the following: + streaming_items_per_frame = ((uint32_t *)payload)[1]; + //its a tiny payload, load the fast-path variables fp_mac_addr_src = *ethernet_mac_addr(); arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); @@ -174,6 +175,24 @@ void handle_udp_data_packet( print_ip_addr(&fp_socket_dst.addr); newline(); printf(" destination udp port: %d\n", fp_socket_dst.port); newline(); + + //setup network and vrt + setup_network(); + setup_vrt(); + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + +} + +static void inline issue_stream_command(size_t nsamps, bool now, bool chain, uint32_t secs, uint32_t ticks, bool start){ + //printf("Stream cmd: nsamps %d, now %d, chain %d, secs %u, ticks %u\n", (int)nsamps, now, chain, secs, ticks); + sr_rx_ctrl->cmd = MK_RX_CMD(nsamps, now, chain); + + if (start) dbsm_start(&dsp_rx_sm); + + sr_rx_ctrl->time_secs = secs; + sr_rx_ctrl->time_ticks = ticks; // enqueue command } #define OTW_GPIO_BANK_TO_NUM(bank) \ @@ -275,7 +294,7 @@ void handle_udp_ctrl_packet( * GPIO ******************************************************************/ case USRP2_CTRL_ID_USE_THESE_GPIO_DDR_SETTINGS_BRO: - hal_gpio_set_ddr( + if (!DEBUG_MODE) hal_gpio_set_ddr( OTW_GPIO_BANK_TO_NUM(ctrl_data_in->data.gpio_config.bank), ctrl_data_in->data.gpio_config.value, ctrl_data_in->data.gpio_config.mask @@ -284,7 +303,7 @@ void handle_udp_ctrl_packet( break; case USRP2_CTRL_ID_SET_YOUR_GPIO_PIN_OUTS_BRO: - hal_gpio_write( + if (!DEBUG_MODE) hal_gpio_write( OTW_GPIO_BANK_TO_NUM(ctrl_data_in->data.gpio_config.bank), ctrl_data_in->data.gpio_config.value, ctrl_data_in->data.gpio_config.mask @@ -302,7 +321,7 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_USE_THESE_ATR_SETTINGS_BRO:{ //setup the atr registers for this bank int bank = OTW_GPIO_BANK_TO_NUM(ctrl_data_in->data.atr_config.bank); - set_atr_regs( + if (!DEBUG_MODE) set_atr_regs( bank, ctrl_data_in->data.atr_config.rx_value, ctrl_data_in->data.atr_config.tx_value @@ -312,7 +331,7 @@ void handle_udp_ctrl_packet( int mask = ctrl_data_in->data.atr_config.mask; for (int i = 0; i < 16; i++){ // set to either GPIO_SEL_SW or GPIO_SEL_ATR - hal_gpio_set_sel(bank, i, (mask & (1 << i)) ? 'a' : 's'); + if (!DEBUG_MODE) hal_gpio_set_sel(bank, i, (mask & (1 << i)) ? 'a' : 's'); } ctrl_data_out.id = USRP2_CTRL_ID_GOT_THE_ATR_SETTINGS_DUDE; } @@ -441,20 +460,69 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_TOTALLY_SETUP_THE_DDC_DUDE; break; - case USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO: - time_secs = ctrl_data_in->data.streaming.secs; - time_ticks = ctrl_data_in->data.streaming.ticks; - streaming_items_per_frame = ctrl_data_in->data.streaming.samples; + /******************************************************************* + * Streaming + ******************************************************************/ + case USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO:{ + + //issue two commands and set the auto-reload flag + if (ctrl_data_in->data.stream_cmd.continuous){ + printf("Setting up continuous streaming...\n"); + printf("items per frame: %d\n", (int)streaming_items_per_frame); + auto_reload_command = true; + streaming_frame_count = FRAMES_PER_CMD; + + issue_stream_command( + streaming_items_per_frame * FRAMES_PER_CMD, + (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now + true, //chain + ctrl_data_in->data.stream_cmd.secs, + ctrl_data_in->data.stream_cmd.ticks, + true //start + ); + + issue_stream_command( + streaming_items_per_frame * FRAMES_PER_CMD, + true, //now + true, //chain + 0, 0, //time does not matter + false + ); - if (ctrl_data_in->data.streaming.enabled == 0){ - stop_rx_cmd(); } + + //issue regular stream commands (split commands if too large) else{ - start_rx_streaming_cmd(); - } + auto_reload_command = false; + size_t num_samps = ctrl_data_in->data.stream_cmd.num_samps; + if (num_samps == 0) num_samps = 1; //FIXME hack, zero is used when stopping continuous streaming but it somehow makes it inifinite + + bool chain = num_samps > MAX_SAMPLES_PER_CMD; + issue_stream_command( + (chain)? streaming_items_per_frame : num_samps, //nsamps + (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now + chain, //chain + ctrl_data_in->data.stream_cmd.secs, + ctrl_data_in->data.stream_cmd.ticks, + false + ); - ctrl_data_out.id = USRP2_CTRL_ID_CONFIGURED_THAT_STREAMING_DUDE; + //handle rest of the samples that did not fit into one cmd + while(chain){ + num_samps -= MAX_SAMPLES_PER_CMD; + chain = num_samps > MAX_SAMPLES_PER_CMD; + issue_stream_command( + (chain)? streaming_items_per_frame : num_samps, //nsamps + true, //now + chain, //chain + 0, 0, //time does not matter + false + ); + } + } + ctrl_data_out.id = USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE; break; + } /******************************************************************* * DUC @@ -529,7 +597,7 @@ eth_pkt_inspector(dbsm_t *sm, int bufno) // In the future, a hardware state machine will do this... if ( //warning! magic numbers approaching.... (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && - ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != 0) + ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != USRP2_INVALID_VRT_HEADER) ) return false; //test if its an ip recovery packet @@ -555,19 +623,11 @@ eth_pkt_inspector(dbsm_t *sm, int bufno) //------------------------------------------------------------------ -static uint16_t get_vrt_packet_words(void){ - return streaming_items_per_frame + \ - USRP2_HOST_RX_VRT_HEADER_WORDS32 + \ - USRP2_HOST_RX_VRT_TRAILER_WORDS32; -} - static bool vrt_has_trailer(void){ return USRP2_HOST_RX_VRT_TRAILER_WORDS32 > 0; } -void -restart_streaming(void) -{ +static void setup_vrt(void){ // setup RX DSP regs sr_rx_ctrl->nsamples_per_pkt = streaming_items_per_frame; sr_rx_ctrl->nchannels = 1; @@ -580,26 +640,6 @@ restart_streaming(void) ); sr_rx_ctrl->vrt_stream_id = 0; sr_rx_ctrl->vrt_trailer = 0; - - streaming_p = true; - streaming_frame_count = FRAMES_PER_CMD; - - sr_rx_ctrl->cmd = - MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, - (time_ticks==TIME_NOW)?1:0, 1); // conditionally set "now" bit, set "chain" bit - - // kick off the state machine - dbsm_start(&dsp_rx_sm); - - sr_rx_ctrl->time_secs = time_secs; - sr_rx_ctrl->time_ticks = time_ticks; // enqueue first of two commands - - // make sure this one and the rest have the "now" and "chain" bits set. - sr_rx_ctrl->cmd = - MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, 1, 1); - - sr_rx_ctrl->time_secs = 0; - sr_rx_ctrl->time_ticks = 0; // enqueue second command } /* @@ -628,23 +668,7 @@ link_changed_callback(int speed) printf("\neth link changed: speed = %d\n", speed); } -void -start_rx_streaming_cmd(void) -{ - /* - * Construct ethernet header and preload into two buffers - */ - struct { - uint32_t ctrl_word; - } mem _AL4; - - memset(&mem, 0, sizeof(mem)); - printf("samples per frame: %d\n", streaming_items_per_frame); - printf("words in a vrt packet %d\n", get_vrt_packet_words()); - mem.ctrl_word = get_vrt_packet_words()*sizeof(uint32_t) | 1 << 16; - - memcpy_wa(buffer_ram(DSP_RX_BUF_0), &mem, sizeof(mem)); - memcpy_wa(buffer_ram(DSP_RX_BUF_1), &mem, sizeof(mem)); +static void setup_network(void){ //setup ethernet header machine sr_udp_sm->eth_hdr.mac_dst_0_1 = (fp_mac_addr_dst.addr[0] << 8) | fp_mac_addr_dst.addr[1]; @@ -676,50 +700,29 @@ start_rx_streaming_cmd(void) sr_udp_sm->udp_hdr.dst_port = fp_socket_dst.port; sr_udp_sm->udp_hdr.length = UDP_SM_INS_UDP_LEN; sr_udp_sm->udp_hdr.checksum = UDP_SM_LAST_WORD; // zero UDP checksum - - if (FW_SETS_SEQNO) - fw_seqno = 0; - - restart_streaming(); } -void -stop_rx_cmd(void) -{ - if (is_streaming()){ - streaming_p = false; - - // no samples, "now", not chained - sr_rx_ctrl->cmd = MK_RX_CMD(0, 1, 0); - - sr_rx_ctrl->time_secs = 0; - sr_rx_ctrl->time_ticks = 0; // enqueue command - } - -} - -#if (FW_SETS_SEQNO) /* - * Debugging ONLY. This will be handled by the tx_protocol_engine. - * * This is called when the DSP Rx chain has filled in a packet. - * We set and increment the seqno, then return false, indicating - * that we didn't handle the packet. A bit of a kludge - * but it should work. */ bool fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false { + // insert the correct length into the control word and vrt header + rx_dsp_buff_t *buff = (rx_dsp_buff_t*)buffer_ram(buf_this); + size_t vrt_len = buffer_pool_status->last_line[buf_this]-1; + buff->control_word = MK_RX_CTRL_WORD(vrt_len); + buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK); + // queue up another rx command when required - if (streaming_p && --streaming_frame_count == 0){ + if (auto_reload_command && --streaming_frame_count == 0){ streaming_frame_count = FRAMES_PER_CMD; sr_rx_ctrl->time_secs = 0; - sr_rx_ctrl->time_ticks = 0; + sr_rx_ctrl->time_ticks = 0; //enqueue last command } return false; // we didn't handle the packet } -#endif inline static void @@ -757,9 +760,9 @@ main(void) #endif output_regs->debug_mux_ctrl = 1; -#if 0 - hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); - hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); +#if DEBUG_MODE + hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); + hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); #endif @@ -774,16 +777,10 @@ main(void) // initialize double buffering state machine for DSP RX -> Ethernet - if (FW_SETS_SEQNO){ dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, &dsp_rx_recv_args, &dsp_rx_send_args, fw_sets_seqno_inspector); - } - else { - dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, - &dsp_rx_recv_args, &dsp_rx_send_args, - dbsm_nop_inspector); - } + // tell app_common that this dbsm could be sending to the ethernet ac_could_be_sending_to_eth = &dsp_rx_sm; @@ -818,7 +815,7 @@ main(void) // FIXME Figure out how to handle this robustly. // Any buffers that are emptying should be allowed to drain... - if (streaming_p){ + if (auto_reload_command){ // restart_streaming(); // FIXME report error } diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/lib/memory_map.h index bb6a1036d..fed1e5259 100644 --- a/firmware/microblaze/lib/memory_map.h +++ b/firmware/microblaze/lib/memory_map.h @@ -525,8 +525,9 @@ typedef struct { volatile uint32_t pad[7]; // Make each structure 16 elements long } sr_rx_ctrl_t; +#define MAX_SAMPLES_PER_CMD 0x3fffffff #define MK_RX_CMD(nsamples, now, chain) \ - ((((now) & 0x1) << 31) | ((chain & 0x1) << 30) | ((nsamples) & 0x3fffffff)) + ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | ((nsamples) & 0x3fffffff)) #define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 2f5d03f7d..05d782abe 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -34,8 +34,9 @@ INCLUDE(CPack) #include after setting vars ######################################################################## SET(RUNTIME_DIR bin) SET(LIBRARY_DIR lib) -SET(RESOURCE_DIR share) -SET(HEADER_DIR include) +SET(INCLUDE_DIR include) +SET(PKG_DATA_DIR share/uhd) +MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") ######################################################################## # Local Include Dir @@ -63,10 +64,10 @@ IF(UNIX) ENDIF(UNIX) IF(WIN32) - ADD_DEFINITIONS(-Dnot=! -Dand=&& -Dor=||) #logical operators ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split + ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) #avoid warnings from std::getenv ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc ENDIF(WIN32) @@ -74,7 +75,7 @@ ENDIF(WIN32) # Setup Boost ######################################################################## SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42") -FIND_PACKAGE(Boost 1.36 REQUIRED +FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS date_time filesystem program_options @@ -126,7 +127,8 @@ INSTALL( ######################################################################## # Add the subdirectories ######################################################################## -ADD_SUBDIRECTORY(apps) +ADD_SUBDIRECTORY(examples) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(test) +ADD_SUBDIRECTORY(utils) diff --git a/host/README b/host/README index f19275c41..cdca42cd0 100644 --- a/host/README +++ b/host/README @@ -6,21 +6,25 @@ The hardware driver for Ettus Research products. ######################################################################## # Supported USRP Motherboards ######################################################################## -USRP2 - gigabit ethernet +USRP2 - udp over gigabit ethernet ######################################################################## # Supported USRP Daughterboards ######################################################################## Basic RX Basic TX +LF RX +LF TX ######################################################################## # CMake Instructions ######################################################################## -cd <uhd_src_dir> +cd uhd/host mkdir build cd build cmake ../ make make test sudo make install + +For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../ diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt new file mode 100644 index 000000000..242857625 --- /dev/null +++ b/host/examples/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp) +TARGET_LINK_LIBRARIES(rx_timed_samples uhd) +INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp new file mode 100644 index 000000000..88e112584 --- /dev/null +++ b/host/examples/rx_timed_samples.cpp @@ -0,0 +1,99 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/safe_main.hpp> +#include <uhd/simple_device.hpp> +#include <uhd/props.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + //variables to be set by po + std::string transport_args; + int seconds_in_future; + size_t total_num_samps; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value<std::string>(&transport_args)->default_value(""), "simple uhd transport args") + ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive") + ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD RX Timed Samples %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") + % transport_args << std::endl; + uhd::simple_device::sptr sdev = uhd::simple_device::make(transport_args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + + //set properties on the device + double rx_rate = sdev->get_rx_rates()[4]; //pick some rate + std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl; + sdev->set_rx_rate(rx_rate); + std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_time_now(uhd::time_spec_t(0)); + + //setup streaming + std::cout << std::endl; + std::cout << boost::format("Begin streaming %u samples, %d seconds in the future...") + % total_num_samps % seconds_in_future << std::endl; + uhd::stream_cmd_t stream_cmd; + stream_cmd.stream_now = false; + stream_cmd.time_spec = uhd::time_spec_t(seconds_in_future); + stream_cmd.continuous = false; + stream_cmd.num_samps = total_num_samps; + sdev->issue_stream_cmd(stream_cmd); + + //loop until total number of samples reached + size_t num_acc_samps = 0; //number of accumulated samples + while(num_acc_samps < total_num_samps){ + uhd::rx_metadata_t md; + std::complex<float> buff[1000]; + size_t num_rx_samps = dev->recv( + boost::asio::buffer(buff, sizeof(buff)), + md, uhd::io_type_t::COMPLEX_FLOAT32 + ); + if (num_rx_samps == 0) continue; //wait for packets with contents + + std::cout << boost::format("Got packet: %u samples, %u secs, %u ticks") + % num_rx_samps % md.time_spec.secs % md.time_spec.ticks << std::endl; + + num_acc_samps += num_rx_samps; + } + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 3d00462cf..b364f78cd 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -17,20 +17,15 @@ ADD_SUBDIRECTORY(transport) +ADD_SUBDIRECTORY(types) ADD_SUBDIRECTORY(usrp) +ADD_SUBDIRECTORY(utils) INSTALL(FILES config.hpp device.hpp - device_addr.hpp - dict.hpp - gain_handler.hpp - metadata.hpp props.hpp simple_device.hpp - time_spec.hpp - types.hpp - utils.hpp wax.hpp - DESTINATION ${HEADER_DIR}/uhd + DESTINATION ${INCLUDE_DIR}/uhd ) diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 10f9c093f..941219ac7 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -1,76 +1,83 @@ -//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_UHD_CONFIG_HPP
-#define INCLUDED_UHD_CONFIG_HPP
-
-// suppress warnings
-#include <boost/config.hpp>
-#ifdef BOOST_MSVC
-# pragma warning(push)
-//# pragma warning(disable: 4511) // copy constructor can't not be generated
-//# pragma warning(disable: 4512) // assignment operator can't not be generated
-//# pragma warning(disable: 4100) // unreferenced formal parameter
-//# pragma warning(disable: 4996) // <symbol> was declared deprecated
-//# pragma warning(disable: 4355) // 'this' : used in base member initializer list
-//# pragma warning(disable: 4706) // assignment within conditional expression
-# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B'
-//# pragma warning(disable: 4127) // conditional expression is constant
-//# pragma warning(disable: 4290) // C++ exception specification ignored except to ...
-//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
-# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ...
-//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
-//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated
-#endif
-
-// http://gcc.gnu.org/wiki/Visibility
-// Generic helper definitions for shared library support
-#if defined _WIN32 || defined __CYGWIN__
- #define UHD_HELPER_DLL_IMPORT __declspec(dllimport)
- #define UHD_HELPER_DLL_EXPORT __declspec(dllexport)
- #define UHD_HELPER_DLL_LOCAL
-#else
- #if __GNUC__ >= 4
- #define UHD_HELPER_DLL_IMPORT __attribute__ ((visibility("default")))
- #define UHD_HELPER_DLL_EXPORT __attribute__ ((visibility("default")))
- #define UHD_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden")))
- #else
- #define UHD_HELPER_DLL_IMPORT
- #define UHD_HELPER_DLL_EXPORT
- #define UHD_HELPER_DLL_LOCAL
- #endif
-#endif
-
-// Now we use the generic helper definitions above to define UHD_API and UHD_LOCAL.
-// UHD_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
-// UHD_LOCAL is used for non-api symbols.
-
-#define UHD_DLL // defined here, put into configuration if we need to make static libs
-
-#ifdef UHD_DLL // defined if UHD is compiled as a DLL
- #ifdef UHD_DLL_EXPORTS // defined if we are building the UHD DLL (instead of using it)
- #define UHD_API UHD_HELPER_DLL_EXPORT
- #else
- #define UHD_API UHD_HELPER_DLL_IMPORT
- #endif // UHD_DLL_EXPORTS
- #define UHD_LOCAL UHD_HELPER_DLL_LOCAL
-#else // UHD_DLL is not defined: this means UHD is a static lib.
- #define UHD_API
- #define UHD_LOCAL
-#endif // UHD_DLL
-
-#endif /* INCLUDED_UHD_CONFIG_HPP */
+// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_CONFIG_HPP +#define INCLUDED_UHD_CONFIG_HPP + +// suppress warnings +#include <boost/config.hpp> +#ifdef BOOST_MSVC +//# pragma warning(push) +//# pragma warning(disable: 4511) // copy constructor can't not be generated +//# pragma warning(disable: 4512) // assignment operator can't not be generated +//# pragma warning(disable: 4100) // unreferenced formal parameter +//# pragma warning(disable: 4996) // <symbol> was declared deprecated +//# pragma warning(disable: 4355) // 'this' : used in base member initializer list +//# pragma warning(disable: 4706) // assignment within conditional expression +# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B' +//# pragma warning(disable: 4127) // conditional expression is constant +//# pragma warning(disable: 4290) // C++ exception specification ignored except to ... +//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored +# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ... +//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated +#endif + +//define logical operators +#ifdef BOOST_MSVC + #define not ! + #define and && + #define or || +#endif + +// http://gcc.gnu.org/wiki/Visibility +// Generic helper definitions for shared library support +#if defined _WIN32 || defined __CYGWIN__ + #define UHD_HELPER_DLL_IMPORT __declspec(dllimport) + #define UHD_HELPER_DLL_EXPORT __declspec(dllexport) + #define UHD_HELPER_DLL_LOCAL +#else + #if __GNUC__ >= 4 + #define UHD_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) + #define UHD_HELPER_DLL_EXPORT __attribute__ ((visibility("default"))) + #define UHD_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden"))) + #else + #define UHD_HELPER_DLL_IMPORT + #define UHD_HELPER_DLL_EXPORT + #define UHD_HELPER_DLL_LOCAL + #endif +#endif + +// Now we use the generic helper definitions above to define UHD_API and UHD_LOCAL. +// UHD_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) +// UHD_LOCAL is used for non-api symbols. + +#define UHD_DLL // defined here, put into configuration if we need to make static libs + +#ifdef UHD_DLL // defined if UHD is compiled as a DLL + #ifdef UHD_DLL_EXPORTS // defined if we are building the UHD DLL (instead of using it) + #define UHD_API UHD_HELPER_DLL_EXPORT + #else + #define UHD_API UHD_HELPER_DLL_IMPORT + #endif // UHD_DLL_EXPORTS + #define UHD_LOCAL UHD_HELPER_DLL_LOCAL +#else // UHD_DLL is not defined: this means UHD is a static lib. + #define UHD_API + #define UHD_LOCAL +#endif // UHD_DLL + +#endif /* INCLUDED_UHD_CONFIG_HPP */ diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 13b40febe..4d4196d98 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -19,9 +19,9 @@ #define INCLUDED_UHD_DEVICE_HPP #include <uhd/config.hpp> -#include <uhd/device_addr.hpp> -#include <uhd/props.hpp> -#include <uhd/metadata.hpp> +#include <uhd/types/device_addr.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/types/io_type.hpp> #include <uhd/wax.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> @@ -38,22 +38,22 @@ class UHD_API device : boost::noncopyable, public wax::obj{ public: typedef boost::shared_ptr<device> sptr; - typedef boost::function<device_addrs_t(const device_addr_t &)> discover_t; + typedef boost::function<device_addrs_t(const device_addr_t &)> find_t; typedef boost::function<sptr(const device_addr_t &)> make_t; /*! * Register a device into the discovery and factory system. * - * \param discover a function that discovers devices + * \param find a function that discovers devices * \param make a factory function that makes a device */ static void register_device( - const discover_t &discover, + const find_t &find, const make_t &make ); /*! - * \brief Discover usrp devices attached to the host. + * \brief Find usrp devices attached to the host. * * The hint device address should be used to narrow down the search * to particular transport types and/or transport arguments. @@ -61,17 +61,17 @@ public: * \param hint a partially (or fully) filled in device address * \return a vector of device addresses for all usrps on the system */ - static device_addrs_t discover(const device_addr_t &hint); + static device_addrs_t find(const device_addr_t &hint); /*! * \brief Create a new usrp device from the device address hint. * - * The make routine will call discover and pick one of the results. + * The make routine will call find and pick one of the results. * By default, the first result will be used to create a new device. * Use the which parameter as an index into the list of results. * * \param hint a partially (or fully) filled in device address - * \param which which address to use when multiple are discovered + * \param which which address to use when multiple are found * \return a shared pointer to a new device instance */ static sptr make(const device_addr_t &hint, size_t which = 0); @@ -91,13 +91,13 @@ public: * * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents - * \param the type of data loaded in the buffer (32fc, 16sc) + * \param io_type the type of data loaded in the buffer * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, const tx_metadata_t &metadata, - const std::string &type = "32fc" + const io_type_t &io_type ) = 0; /*! @@ -123,13 +123,13 @@ public: * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer - * \param the type of data to fill into the buffer (32fc, 16sc) + * \param io_type the type of data to fill into the buffer * \return the number of samples received */ virtual size_t recv( const boost::asio::mutable_buffer &buff, rx_metadata_t &metadata, - const std::string &type = "32fc" + const io_type_t &io_type ) = 0; }; diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp deleted file mode 100644 index 7673faff0..000000000 --- a/host/include/uhd/device_addr.hpp +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_DEVICE_ADDR_HPP -#define INCLUDED_UHD_DEVICE_ADDR_HPP - -#include <uhd/config.hpp> -#include <uhd/dict.hpp> -#include <boost/cstdint.hpp> -#include <string> -#include <iostream> -#include <vector> - -namespace uhd{ - - /*! - * Wrapper for an ethernet mac address. - * Provides conversion between string and binary formats. - */ - struct UHD_API mac_addr_t{ - boost::uint8_t mac_addr[6]; - mac_addr_t(const std::string &mac_addr_str = "00:00:00:00:00:00"); - std::string to_string(void) const; - }; - - /*! - * The device address args are just a mapping of key/value string pairs. - * When left empty, the discovery routine will try to find all usrps. - * The discovery can be narrowed down by specifying the transport type arguments. - * - * For example, to access a specific usrp2 one would specify the transport type - * ("type", "udp") and the transport args ("addr", "<resolvable_hostname_or_addr>"). - */ - typedef dict<std::string, std::string> device_addr_t; - typedef std::vector<device_addr_t> device_addrs_t; - - /*! - * Function to turn a device address into a string. - * Just having the operator<< below should be sufficient. - * However, boost format seems to complain with the % - * and this is just easier because it works. - * \param device_addr a device address instance - * \return the string representation - */ - namespace device_addr{ - UHD_API std::string to_string(const device_addr_t &device_addr); - } - -} //namespace uhd - -//ability to use types with stream operators -UHD_API std::ostream& operator<<(std::ostream &, const uhd::device_addr_t &); -UHD_API std::ostream& operator<<(std::ostream &, const uhd::mac_addr_t &); - -#endif /* INCLUDED_UHD_DEVICE_ADDR_HPP */ diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp deleted file mode 100644 index 6d80f070d..000000000 --- a/host/include/uhd/metadata.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_METADATA_HPP -#define INCLUDED_UHD_METADATA_HPP - -#include <uhd/config.hpp> -#include <uhd/time_spec.hpp> - -namespace uhd{ - -/*! - * RX metadata structure for describing sent IF data. - * Includes stream ID, time specification, and fragmentation flags. - * The receive routines will convert IF data headers into metadata. - */ -struct UHD_API rx_metadata_t{ - boost::uint32_t stream_id; - time_spec_t time_spec; - bool has_stream_id; - bool has_time_spec; - bool is_fragment; - - //default constructor - rx_metadata_t(void); -}; - -/*! - * TX metadata structure for describing received IF data. - * Includes stream ID, time specification, and burst flags. - * The send routines will convert the metadata to IF data headers. - */ -struct UHD_API tx_metadata_t{ - boost::uint32_t stream_id; - time_spec_t time_spec; - bool has_stream_id; - bool has_time_spec; - bool start_of_burst; - bool end_of_burst; - - //default constructor - tx_metadata_t(void); -}; - -} //namespace uhd - -#endif /* INCLUDED_UHD_METADATA_HPP */ diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index 41e0eff63..01746f853 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -76,8 +76,6 @@ namespace uhd{ MBOARD_PROP_TX_DBOARD, //ro, wax::obj MBOARD_PROP_TX_DBOARD_NAMES, //ro, prop_names_t MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t - MBOARD_PROP_PPS_SOURCE_NAMES, //ro, prop_names_t - MBOARD_PROP_REF_SOURCE_NAMES, //ro, prop_names_t MBOARD_PROP_TIME_NOW, //wo, time_spec_t MBOARD_PROP_TIME_NEXT_PPS //wo, time_spec_t }; diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp index ad25eccdc..52928367a 100644 --- a/host/include/uhd/simple_device.hpp +++ b/host/include/uhd/simple_device.hpp @@ -20,7 +20,9 @@ #include <uhd/config.hpp> #include <uhd/device.hpp> -#include <uhd/types.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/tune_result.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <vector> @@ -43,10 +45,15 @@ public: virtual std::string get_name(void) = 0; /******************************************************************* + * Timing + ******************************************************************/ + virtual void set_time_now(const time_spec_t &time_spec) = 0; + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /******************************************************************* * Streaming ******************************************************************/ - virtual void set_streaming(bool enb) = 0; - virtual bool get_streaming(void) = 0; + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; /******************************************************************* * RX methods diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 7f5db2128..14b5ccd29 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -17,9 +17,10 @@ INSTALL(FILES + if_addrs.hpp smart_buffer.hpp udp_simple.hpp udp_zero_copy.hpp vrt.hpp - DESTINATION ${HEADER_DIR}/uhd/transport + DESTINATION ${INCLUDE_DIR}/uhd/transport ) diff --git a/host/lib/metadata.cpp b/host/include/uhd/transport/if_addrs.hpp index 40fdb7c73..fbbb35e1d 100644 --- a/host/lib/metadata.cpp +++ b/host/include/uhd/transport/if_addrs.hpp @@ -15,23 +15,33 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/metadata.hpp> - -using namespace uhd; - -rx_metadata_t::rx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - is_fragment = false; -} - -tx_metadata_t::tx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - start_of_burst = false; - end_of_burst = false; -} +#ifndef INCLUDED_UHD_IFADDRS_HPP +#define INCLUDED_UHD_IFADDRS_HPP + +#include <uhd/config.hpp> +#include <string> +#include <vector> + +namespace uhd{ namespace transport{ + + /*! + * The address for a network interface. + */ + struct UHD_API if_addrs_t{ + std::string inet; + std::string mask; + std::string bcast; + if_addrs_t(void); + }; + + /*! + * Get a list of network interface addresses. + * The internal implementation is system-dependent. + * \return a vector of if addrs + */ + UHD_API std::vector<if_addrs_t> get_if_addrs(void); + +}} //namespace + + +#endif /* INCLUDED_UHD_IFADDRS_HPP */ diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp index 9e1032feb..a9bc259e9 100644 --- a/host/include/uhd/transport/smart_buffer.hpp +++ b/host/include/uhd/transport/smart_buffer.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP #define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP -#include <boost/asio.hpp> +#include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp index 40e60d091..793ec4fd7 100644 --- a/host/include/uhd/transport/udp_simple.hpp +++ b/host/include/uhd/transport/udp_simple.hpp @@ -19,7 +19,7 @@ #define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP #include <uhd/config.hpp> -#include <boost/asio.hpp> +#include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 03d89b3a5..0441a8e74 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -20,7 +20,7 @@ #include <uhd/config.hpp> #include <uhd/transport/smart_buffer.hpp> -#include <boost/asio.hpp> +#include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index db2c57eba..04945b347 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -19,7 +19,7 @@ #define INCLUDED_UHD_TRANSPORT_VRT_HPP #include <uhd/config.hpp> -#include <uhd/metadata.hpp> +#include <uhd/types/metadata.hpp> #include <cstddef> namespace uhd{ namespace transport{ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt new file mode 100644 index 000000000..e4cdf2cef --- /dev/null +++ b/host/include/uhd/types/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +INSTALL(FILES + clock_config.hpp + device_addr.hpp + dict.hpp + io_type.hpp + mac_addr.hpp + metadata.hpp + otw_type.hpp + ranges.hpp + stream_cmd.hpp + time_spec.hpp + tune_result.hpp + DESTINATION ${INCLUDE_DIR}/uhd/types +) diff --git a/host/include/uhd/types/clock_config.hpp b/host/include/uhd/types/clock_config.hpp new file mode 100644 index 000000000..42d74ad90 --- /dev/null +++ b/host/include/uhd/types/clock_config.hpp @@ -0,0 +1,50 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_CLOCK_CONFIG_HPP +#define INCLUDED_UHD_TYPES_CLOCK_CONFIG_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + + /*! + * Clock configuration settings: + * The source for the 10MHz reference clock. + * The source and polarity for the PPS clock. + */ + struct UHD_API clock_config_t{ + enum ref_source_t { + REF_INT = 'i', //internal reference + REF_SMA = 's', //external sma port + REF_MIMO = 'm' //mimo cable (usrp2 only) + } ref_source; + enum pps_source_t { + PPS_INT = 'i', //there is no internal + PPS_SMA = 's', //external sma port + PPS_MIMO = 'm' //mimo cable (usrp2 only) + } pps_source; + enum pps_polarity_t { + PPS_NEG = 'n', //negative edge + PPS_POS = 'p' //positive edge + } pps_polarity; + clock_config_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_CLOCK_CONFIG_HPP */ diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp new file mode 100644 index 000000000..1162884fb --- /dev/null +++ b/host/include/uhd/types/device_addr.hpp @@ -0,0 +1,70 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP +#define INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP + +#include <uhd/config.hpp> +#include <uhd/types/dict.hpp> +#include <vector> +#include <string> + +namespace uhd{ + + /*! + * Mapping of key/value pairs for locating devices on the system. + * When left empty, the device discovery routines will search + * all available transports on the system (ethernet, usb...). + * + * To narrow down the discovery process to a particular device, + * specify a transport key/value pair specific to your device. + * Ex, to find a usrp2: my_dev_addr["addr"] = <resolvable_hostname_or_ip> + * + * The device address can also be used to pass arguments into + * the transport layer control to set (for example) buffer sizes. + */ + class UHD_API device_addr_t : public dict<std::string, std::string>{ + public: + + /*! + * Convert a device address into a printable string. + * \return string good for use with std::cout << + */ + std::string to_string(void) const; + + /*! + * Convert the device address into an args string. + * The args string contains delimiter symbols. + * \return a string with delimiter markup + */ + std::string to_args_str(void) const; + + /*! + * Make a device address from an args string. + * The args string contains delimiter symbols. + * \param args_str the arguments string + * \return the new device address + */ + static device_addr_t from_args_str(const std::string &args_str); + }; + + //handy typedef for a vector of device addresses + typedef std::vector<device_addr_t> device_addrs_t; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP */ diff --git a/host/include/uhd/dict.hpp b/host/include/uhd/types/dict.hpp index f08493952..7fb712e76 100644 --- a/host/include/uhd/dict.hpp +++ b/host/include/uhd/types/dict.hpp @@ -15,13 +15,14 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_DICT_HPP -#define INCLUDED_UHD_DICT_HPP +#ifndef INCLUDED_UHD_TYPES_DICT_HPP +#define INCLUDED_UHD_TYPES_DICT_HPP -#include <list> -#include <vector> -#include <stdexcept> +#include <uhd/config.hpp> #include <boost/foreach.hpp> +#include <stdexcept> +#include <vector> +#include <list> namespace uhd{ @@ -151,4 +152,4 @@ namespace uhd{ } //namespace uhd -#endif /* INCLUDED_UHD_DICT_HPP */ +#endif /* INCLUDED_UHD_TYPES_DICT_HPP */ diff --git a/host/include/uhd/types/io_type.hpp b/host/include/uhd/types/io_type.hpp new file mode 100644 index 000000000..930394d1b --- /dev/null +++ b/host/include/uhd/types/io_type.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_IO_TYPE_HPP +#define INCLUDED_UHD_TYPES_IO_TYPE_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + + /*! + * Used to specify the IO type with device send/recv. + */ + class UHD_API io_type_t{ + public: + + /*! + * Built in IO types known to the system. + */ + enum tid_t{ + CUSTOM_TYPE = '?', + COMPLEX_FLOAT32 = 'f', + COMPLEX_INT16 = 's', + COMPLEX_INT8 = 'b' + }; + + /*! + * The size of this io type in bytes. + */ + const size_t size; + + /*! + * The type id of this io type. + * Good for using with switch statements. + */ + const tid_t tid; + + /*! + * Create an io type from a built-in type id. + * \param tid a type id known to the system + */ + io_type_t(tid_t tid); + + /*! + * Create an io type from attributes. + * The tid will be set to custom. + * \param size the size in bytes + */ + io_type_t(size_t size); + + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_IO_TYPE_HPP */ diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp new file mode 100644 index 000000000..3cd1fe86b --- /dev/null +++ b/host/include/uhd/types/mac_addr.hpp @@ -0,0 +1,68 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_MAC_ADDR_HPP +#define INCLUDED_UHD_TYPES_MAC_ADDR_HPP + +#include <uhd/config.hpp> +#include <boost/cstdint.hpp> +#include <string> + +namespace uhd{ + + /*! + * Wrapper for an ethernet mac address. + * Provides conversion between string and binary formats. + */ + class UHD_API mac_addr_t{ + public: + static const size_t hlen = 6; + + /*! + * Create a mac address a byte array. + * \param bytes a pointer for the byte array + * \return a new mac address + */ + static mac_addr_t from_bytes(const boost::uint8_t *bytes); + + /*! + * Create a mac address from a string. + * \param mac_addr_str the string with delimiters + * \return a new mac address + */ + static mac_addr_t from_string(const std::string &mac_addr_str); + + /*! + * Get the byte representation of the mac address. + * \return a pointer to the internal byte array + */ + const boost::uint8_t *to_bytes(void) const; + + /*! + * Get the string representation of this mac address. + * \return a string with delimiters + */ + std::string to_string(void) const; + + private: + mac_addr_t(const boost::uint8_t *bytes); //private constructor + boost::uint8_t _bytes[hlen]; //internal representation + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_MAC_ADDR_HPP */ diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp new file mode 100644 index 000000000..6e93040d9 --- /dev/null +++ b/host/include/uhd/types/metadata.hpp @@ -0,0 +1,61 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_METADATA_HPP +#define INCLUDED_UHD_TYPES_METADATA_HPP + +#include <uhd/config.hpp> +#include <uhd/types/time_spec.hpp> + +namespace uhd{ + + /*! + * RX metadata structure for describing sent IF data. + * Includes stream ID, time specification, and fragmentation flags. + * The receive routines will convert IF data headers into metadata. + */ + struct UHD_API rx_metadata_t{ + boost::uint32_t stream_id; + time_spec_t time_spec; + bool has_stream_id; + bool has_time_spec; + bool is_fragment; + + //default constructor + rx_metadata_t(void); + }; + + /*! + * TX metadata structure for describing received IF data. + * Includes stream ID, time specification, and burst flags. + * The send routines will convert the metadata to IF data headers. + */ + struct UHD_API tx_metadata_t{ + boost::uint32_t stream_id; + time_spec_t time_spec; + bool has_stream_id; + bool has_time_spec; + bool start_of_burst; + bool end_of_burst; + + //default constructor + tx_metadata_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_METADATA_HPP */ diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp new file mode 100644 index 000000000..f10664584 --- /dev/null +++ b/host/include/uhd/types/otw_type.hpp @@ -0,0 +1,63 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_OTW_TYPE_HPP +#define INCLUDED_UHD_TYPES_OTW_TYPE_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + + /*! + * Description for over-the-wire integers: + * The DSP units in the FPGA deal with signed 16-bit integers. + * The width and shift define the translation between OTW and DSP, + * defined by the following relation: otw_int = dsp_int >> shift + * + * Note: possible combinations of width, shift, and byteorder + * depend on the internals of the FPGA. Not all are supported! + */ + struct UHD_API otw_type_t{ + + /*! + * Width of an over-the-wire integer in bits. + */ + size_t width; //in bits + + /*! + * Shift of an over-the-wire integer in bits. + * otw_int = dsp_int >> shift + * dsp_int = otw_int << shift + */ + size_t shift; //in bits + + /*! + * Constants for byte order (borrowed from numpy's dtype) + */ + enum /*bo_t*/ { + BO_NATIVE = '=', + BO_LITTLE_ENDIAN = '<', + BO_BIG_ENDIAN = '>', + BO_NOT_APPLICABLE = '|' + } byteorder; + + otw_type_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_OTW_TYPE_HPP */ diff --git a/host/include/uhd/types.hpp b/host/include/uhd/types/ranges.hpp index 1439f57a1..a2057d1c8 100644 --- a/host/include/uhd/types.hpp +++ b/host/include/uhd/types/ranges.hpp @@ -15,17 +15,13 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_TYPES_HPP -#define INCLUDED_UHD_TYPES_HPP +#ifndef INCLUDED_UHD_TYPES_RANGES_HPP +#define INCLUDED_UHD_TYPES_RANGES_HPP #include <uhd/config.hpp> -#include <string> namespace uhd{ - typedef float gain_t; //TODO REMOVE - typedef double freq_t; //TODO REMOVE - /*! * The gain range struct describes possible gain settings. * The mimumum gain, maximum gain, and step size are in dB. @@ -45,39 +41,6 @@ namespace uhd{ freq_range_t(double min = 0.0, double max = 0.0); }; - /*! - * The tune result struct holds result of a 2-phase tuning: - * The struct hold the result of tuning the dboard as - * the target and actual intermediate frequency. - * The struct hold the result of tuning the DDC/DUC as - * the target and actual digital converter frequency. - * It also tell us weather or not the spectrum is inverted. - */ - struct UHD_API tune_result_t{ - double target_inter_freq; - double actual_inter_freq; - double target_dxc_freq; - double actual_dxc_freq; - bool spectrum_inverted; - tune_result_t(void); - }; - - /*! - * Clock configuration settings: - * The source for the 10MHz reference clock. - * The source and polarity for the PPS clock. - * Possible settings for the reference and pps source - * are implementation specific motherboard properties. - * See the MBOARD_PROP_XXX_SOURCE_NAMES properties. - */ - struct clock_config_t{ - enum polarity_t {POLARITY_NEG, POLARITY_POS}; - std::string ref_source; - std::string pps_source; - polarity_t pps_polarity; - clock_config_t(void); - }; - } //namespace uhd -#endif /* INCLUDED_UHD_TYPES_HPP */ +#endif /* INCLUDED_UHD_TYPES_RANGES_HPP */ diff --git a/host/include/uhd/types/stream_cmd.hpp b/host/include/uhd/types/stream_cmd.hpp new file mode 100644 index 000000000..97a6b73ce --- /dev/null +++ b/host/include/uhd/types/stream_cmd.hpp @@ -0,0 +1,56 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_STREAM_CMD_HPP +#define INCLUDED_UHD_TYPES_STREAM_CMD_HPP + +#include <uhd/config.hpp> +#include <uhd/types/time_spec.hpp> + +namespace uhd{ + + /*! + * Command struct for configuration and control of streaming: + * + * A stream command defines how the device sends samples to the host. + * Streaming is controlled by submitting a stream command to the rx dsp. + * Granular control over what the device streams to the host can be + * achieved through submission of multiple (carefully-crafted) commands. + * + * The stream_now parameter controls when the stream begins. + * When true, the device will begin streaming ASAP. When false, + * the device will begin streaming at a time specified by time_spec. + * + * The continuous parameter controls the number of samples received. + * When true, the device continues streaming indefinitely. When false, + * the device will stream the number of samples specified by num_samps. + * + * Standard usage case: + * To start continuous streaming, set stream_now to true and continuous to true. + * To end continuous streaming, set stream_now to true and continuous to false. + */ + struct UHD_API stream_cmd_t{ + bool stream_now; + time_spec_t time_spec; + bool continuous; + size_t num_samps; + stream_cmd_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_STREAM_CMD_HPP */ diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index c1e7cf3a1..8c8f2bc25 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_TIME_SPEC_HPP -#define INCLUDED_UHD_TIME_SPEC_HPP +#ifndef INCLUDED_UHD_TYPES_TIME_SPEC_HPP +#define INCLUDED_UHD_TYPES_TIME_SPEC_HPP #include <uhd/config.hpp> #include <boost/cstdint.hpp> @@ -35,17 +35,11 @@ namespace uhd{ boost::uint32_t ticks; /*! - * Create a time_spec_t that holds a wildcard time. - * This will have implementation-specific meaning. - */ - time_spec_t(void); - - /*! * Create a time_spec_t from seconds and ticks. - * \param new_secs the new seconds + * \param new_secs the new seconds (default = 0) * \param new_ticks the new ticks (default = 0) */ - time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks = 0); + time_spec_t(boost::uint32_t new_secs = 0, boost::uint32_t new_ticks = 0); /*! * Create a time_spec_t from boost posix time. @@ -58,4 +52,4 @@ namespace uhd{ } //namespace uhd -#endif /* INCLUDED_UHD_TIME_SPEC_HPP */ +#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */ diff --git a/host/include/uhd/types/tune_result.hpp b/host/include/uhd/types/tune_result.hpp new file mode 100644 index 000000000..31742e1af --- /dev/null +++ b/host/include/uhd/types/tune_result.hpp @@ -0,0 +1,44 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_RESULT_HPP +#define INCLUDED_UHD_TYPES_TUNE_RESULT_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + + /*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ + struct UHD_API tune_result_t{ + double target_inter_freq; + double actual_inter_freq; + double target_dxc_freq; + double actual_dxc_freq; + bool spectrum_inverted; + tune_result_t(void); + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_TUNE_RESULT_HPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 4e0a92365..bab01fdeb 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -23,5 +23,5 @@ INSTALL(FILES dboard_manager.hpp usrp1e.hpp usrp2.hpp - DESTINATION ${HEADER_DIR}/uhd/usrp + DESTINATION ${INCLUDE_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 4b2392bee..afacaf8ff 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -26,8 +26,6 @@ namespace uhd{ namespace usrp{ typedef boost::uint16_t dboard_id_t; -static const dboard_id_t ID_NONE = 0xffff; //TODO: REMOVE ME - namespace dboard_id{ static const dboard_id_t NONE = 0xffff; UHD_API std::string to_string(const dboard_id_t &id); diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index 6a105d1de..c7c091220 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -42,7 +42,7 @@ public: /*! * Register a dboard into the system. - * + * For single subdevice boards, omit subdev_names. * \param dboard_id the dboard id (rx or tx) * \param dboard_ctor the dboard constructor function pointer * \param name the canonical name for the dboard represented @@ -52,7 +52,7 @@ public: dboard_id_t dboard_id, dboard_ctor_t dboard_ctor, const std::string &name, - const prop_names_t &subdev_names + const prop_names_t &subdev_names = prop_names_t(1, "") ); /*! diff --git a/host/include/uhd/usrp/usrp1e.hpp b/host/include/uhd/usrp/usrp1e.hpp index f4cc39d8e..75da58453 100644 --- a/host/include/uhd/usrp/usrp1e.hpp +++ b/host/include/uhd/usrp/usrp1e.hpp @@ -29,12 +29,11 @@ namespace uhd{ namespace usrp{ class UHD_API usrp1e : public device{ public: /*! - * Discover usrp1e devices on the system via the device node. - * This static method will be called by the device::discover. + * Find usrp1e devices on the system via the device node. * \param hint a device addr with the usrp1e address filled in * \return a vector of device addresses for all usrp1es found */ - static device_addrs_t discover(const device_addr_t &hint); + static device_addrs_t find(const device_addr_t &hint); /*! * Make a usrp1e from a device address. diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp index 277ddc131..613b40ae3 100644 --- a/host/include/uhd/usrp/usrp2.hpp +++ b/host/include/uhd/usrp/usrp2.hpp @@ -29,17 +29,16 @@ namespace uhd{ namespace usrp{ class UHD_API usrp2 : public device{ public: /*! - * Discover usrp2 devices over the ethernet. + * Find usrp2 devices over the ethernet. * * Recommended key/value pairs for the device hint address: * hint["addr"] = address, where address is a resolvable address * or ip address, which may or may not be a broadcast address. * - * This static method will be called by the device::discover. * \param hint a device addr with the usrp2 address filled in * \return a vector of device addresses for all usrp2s found */ - static device_addrs_t discover(const device_addr_t &hint); + static device_addrs_t find(const device_addr_t &hint); /*! * Make a usrp2 from a device address. diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt new file mode 100644 index 000000000..1b673f44a --- /dev/null +++ b/host/include/uhd/utils/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +INSTALL(FILES + algorithm.hpp + assert.hpp + gain_handler.hpp + safe_main.hpp + static.hpp + tune_helper.hpp + DESTINATION ${INCLUDE_DIR}/uhd/utils +) diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp new file mode 100644 index 000000000..6635c8a4a --- /dev/null +++ b/host/include/uhd/utils/algorithm.hpp @@ -0,0 +1,60 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_ALGORITHM_HPP +#define INCLUDED_UHD_UTILS_ALGORITHM_HPP + +#include <algorithm> + +/*! + * Useful templated functions and classes that I like to pretend are part of stl + */ +namespace std{ + + template<class T, class InputIterator, class Function> + T reduce(InputIterator first, InputIterator last, Function fcn, T init = 0){ + T tmp = init; + for ( ; first != last; ++first ){ + tmp = fcn(tmp, *first); + } + return tmp; + } + + template<class T, class Iterable, class Function> + T reduce(Iterable iterable, Function fcn, T init = 0){ + return reduce(iterable.begin(), iterable.end(), fcn, init); + } + + template<class T, class InputIterator> + bool has(InputIterator first, InputIterator last, const T &elem){ + return last != std::find(first, last, elem); + } + + template<class T, class Iterable> + bool has(const Iterable &iterable, const T &elem){ + return has(iterable.begin(), iterable.end(), elem); + } + + template<typename T> T signum(T n){ + if (n < 0) return -1; + if (n > 0) return 1; + return 0; + } + +}//namespace std + +#endif /* INCLUDED_UHD_UTILS_ALGORITHM_HPP */ diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils/assert.hpp index e5333539f..842ed8dfa 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils/assert.hpp @@ -15,85 +15,31 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_UTILS_HPP -#define INCLUDED_UHD_UTILS_HPP +#ifndef INCLUDED_UHD_UTILS_ASSERT_HPP +#define INCLUDED_UHD_UTILS_ASSERT_HPP -#include <uhd/config.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <boost/lexical_cast.hpp> #include <boost/current_function.hpp> #include <stdexcept> -#include <algorithm> - -/*! - * Defines a function that implements the "construct on first use" idiom - * \param _t the type definition for the instance - * \param _x the name of the defined function - * \return a reference to the lazy instance - */ -#define STATIC_INSTANCE(_t, _x) static _t &_x(){static _t _x; return _x;} -/*! - * Defines a static code block that will be called before main() - * \param _x the name of the defined struct (must be unique in file) - */ -#define STATIC_BLOCK(_x) static struct _x{_x();}_x;_x::_x() - -/*! - * Useful templated functions and classes that I like to pretend are part of stl - */ -namespace std{ +namespace uhd{ class assert_error : public std::logic_error{ public: - explicit assert_error(const string& what_arg) : logic_error(what_arg){ + explicit assert_error(const std::string& what_arg) : logic_error(what_arg){ /* NOP */ } }; #define ASSERT_THROW(_x) if (not (_x)) { \ - throw std::assert_error(str(boost::format( \ + throw uhd::assert_error(str(boost::format( \ "Assertion Failed:\n %s:%d\n %s\n ---> %s <---" \ ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ } - template<class T, class InputIterator, class Function> - T reduce(InputIterator first, InputIterator last, Function fcn, T init = 0){ - T tmp = init; - for ( ; first != last; ++first ){ - tmp = fcn(tmp, *first); - } - return tmp; - } - - template<class T, class Iterable, class Function> - T reduce(Iterable iterable, Function fcn, T init = 0){ - return reduce(iterable.begin(), iterable.end(), fcn, init); - } - - template<class T, class InputIterator> - bool has(InputIterator first, InputIterator last, const T &elem){ - return last != std::find(first, last, elem); - } - - template<class T, class Iterable> - bool has(const Iterable &iterable, const T &elem){ - return has(iterable.begin(), iterable.end(), elem); - } - - template<typename T> T signum(T n){ - if (n < 0) return -1; - if (n > 0) return 1; - return 0; - } - -}//namespace std - -#include <boost/format.hpp> -#include <boost/foreach.hpp> -#include <boost/lexical_cast.hpp> - -namespace uhd{ - /*! * Check that an element is found in a container. * If not, throw a meaningful assertion error. @@ -116,7 +62,7 @@ namespace uhd{ if (e != iterable.begin()[0]) possible_values += ", "; possible_values += boost::lexical_cast<std::string>(e); } - throw std::assert_error(str(boost::format( + throw uhd::assert_error(str(boost::format( "Error: %s is not a valid %s. " "Possible values are: [%s]." ) @@ -127,4 +73,4 @@ namespace uhd{ }//namespace uhd -#endif /* INCLUDED_UHD_UTILS_HPP */ +#endif /* INCLUDED_UHD_UTILS_ASSERT_HPP */ diff --git a/host/include/uhd/gain_handler.hpp b/host/include/uhd/utils/gain_handler.hpp index 65d6cecf9..f4629e6a7 100644 --- a/host/include/uhd/gain_handler.hpp +++ b/host/include/uhd/utils/gain_handler.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_GAIN_HANDLER_HPP -#define INCLUDED_UHD_GAIN_HANDLER_HPP +#ifndef INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP +#define INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP #include <uhd/config.hpp> #include <uhd/wax.hpp> @@ -86,5 +86,5 @@ public: } //namespace uhd -#endif /* INCLUDED_UHD_GAIN_HANDLER_HPP */ +#endif /* INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP */ diff --git a/host/include/uhd/utils/safe_main.hpp b/host/include/uhd/utils/safe_main.hpp new file mode 100644 index 000000000..b682aa540 --- /dev/null +++ b/host/include/uhd/utils/safe_main.hpp @@ -0,0 +1,44 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_SAFE_MAIN_HPP +#define INCLUDED_UHD_UTILS_SAFE_MAIN_HPP + +#include <uhd/config.hpp> +#include <iostream> +#include <stdexcept> + +/*! + * Defines a safe wrapper that places a catch-all around main. + * If an exception is thrown, it prints to stderr and returns. + * Usage: int UHD_SAFE_MAIN(int argc, char *argv[]){ main code here } + * \param _argc the declaration for argc + * \param _argv the declaration for argv + */ +#define UHD_SAFE_MAIN(_argc, _argv) _main(int, char*[]); \ +int main(int argc, char *argv[]){ \ + try { \ + return _main(argc, argv); \ + } catch(const std::exception &e) { \ + std::cerr << "Error: " << e.what() << std::endl; \ + } catch(...) { \ + std::cerr << "Error: unknown exception" << std::endl; \ + } \ + return ~0; \ +} int _main(_argc, _argv) + +#endif /* INCLUDED_UHD_UTILS_SAFE_MAIN_HPP */ diff --git a/host/include/uhd/utils/static.hpp b/host/include/uhd/utils/static.hpp new file mode 100644 index 000000000..c61f10884 --- /dev/null +++ b/host/include/uhd/utils/static.hpp @@ -0,0 +1,37 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_STATIC_HPP +#define INCLUDED_UHD_UTILS_STATIC_HPP + +#include <uhd/config.hpp> + +/*! + * Defines a function that implements the "construct on first use" idiom + * \param _t the type definition for the instance + * \param _x the name of the defined function + * \return a reference to the lazy instance + */ +#define UHD_SINGLETON_FCN(_t, _x) static _t &_x(){static _t _x; return _x;} + +/*! + * Defines a static code block that will be called before main() + * \param _x the name of the defined struct (must be unique in file) + */ +#define UHD_STATIC_BLOCK(_x) static struct _x{_x();}_x;_x::_x() + +#endif /* INCLUDED_UHD_UTILS_STATIC_HPP */ diff --git a/host/include/uhd/utils/tune_helper.hpp b/host/include/uhd/utils/tune_helper.hpp new file mode 100644 index 000000000..958d1eceb --- /dev/null +++ b/host/include/uhd/utils/tune_helper.hpp @@ -0,0 +1,79 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_TUNE_HELPER_HPP +#define INCLUDED_UHD_UTILS_TUNE_HELPER_HPP + +#include <uhd/config.hpp> +#include <uhd/wax.hpp> +#include <uhd/types/tune_result.hpp> + +namespace uhd{ + +/*! + * Tune a rx chain to the desired frequency: + * The IF of the subdevice is set as close as possible to + * the given target frequency + the LO offset (when applicable). + * The ddc cordic is setup to bring the IF down to baseband. + * \param subdev the dboard subdevice object with properties + * \param ddc the ddc properties object (with "if_rate", "bb_rate", "freq") + * \param target_freq the desired center frequency + * \param lo_offset an offset for the subdevice IF from center + * \return a tune result struct + */ +UHD_API tune_result_t tune_rx_subdev_and_ddc( + wax::obj subdev, wax::obj ddc, + double target_freq, double lo_offset +); + +/*! + * Tune a rx chain to the desired frequency: + * Same as the above, except the LO offset + * is calculated based on the subdevice and BW. + */ +UHD_API tune_result_t tune_rx_subdev_and_ddc( + wax::obj subdev, wax::obj ddc, double target_freq +); + +/*! + * Tune a tx chain to the desired frequency: + * The IF of the subdevice is set as close as possible to + * the given target frequency + the LO offset (when applicable). + * The duc cordic is setup to bring the baseband up to IF. + * \param subdev the dboard subdevice object with properties + * \param duc the duc properties object (with "if_rate", "bb_rate", "freq") + * \param target_freq the desired center frequency + * \param lo_offset an offset for the subdevice IF from center + * \return a tune result struct + */ +UHD_API tune_result_t tune_tx_subdev_and_duc( + wax::obj subdev, wax::obj duc, + double target_freq, double lo_offset +); + +/*! + * Tune a tx chain to the desired frequency: + * Same as the above, except the LO offset + * is calculated based on the subdevice and BW. + */ +UHD_API tune_result_t tune_tx_subdev_and_duc( + wax::obj subdev, wax::obj duc, double target_freq +); + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_TUNE_HELPER_HPP */ diff --git a/host/include/uhd/wax.hpp b/host/include/uhd/wax.hpp index 30645f491..14e6734a5 100644 --- a/host/include/uhd/wax.hpp +++ b/host/include/uhd/wax.hpp @@ -38,6 +38,10 @@ * * Property nesting occurs when a WAX object gets another object's link. * This special link is obtained through a call to my_obj.get_link(). + * + * Note: Do not put a class derived from wax::obj into an stl container. + * MSVC will compile the code, but the binaries will crash at runtime. + * Rather, use pointers or smart pointers to instances of the derived class. */ namespace wax{ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 46cce729e..323b69b14 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -20,14 +20,13 @@ ######################################################################## SET(libuhd_sources device.cpp - device_addr.cpp gain_handler.cpp load_modules.cpp - metadata.cpp simple_device.cpp - time_spec.cpp + tune_helper.cpp types.cpp wax.cpp + transport/if_addrs.cpp transport/udp_simple.cpp transport/vrt.cpp usrp/dboard/basic.cpp @@ -83,22 +82,42 @@ ENDIF(HAS_USRP1E_REQUIRED_HEADERS) ######################################################################## # Setup defines for module loading ######################################################################## -INCLUDE(CheckIncludeFileCXX) +MESSAGE(STATUS "Configuring module loading...") +INCLUDE(CheckIncludeFileCXX) CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H) -CHECK_INCLUDE_FILE_CXX(Winbase.h HAVE_WINBASE_H) +CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H) IF(HAVE_DLFCN_H) - MESSAGE(STATUS "Module loading supported through dlopen...") + MESSAGE(STATUS " Module loading supported through dlopen.") ADD_DEFINITIONS(-DHAVE_DLFCN_H) -ELSEIF(HAVE_WINBASE_H) - MESSAGE(STATUS "Module loading supported through LoadLibrary...") - ADD_DEFINITIONS(-DHAVE_WINBASE_H) +ELSEIF(HAVE_WINDOWS_H) + MESSAGE(STATUS " Module loading supported through LoadLibrary.") + ADD_DEFINITIONS(-DHAVE_WINDOWS_H) ELSE(HAVE_DLFCN_H) - MESSAGE(STATUS "Module loading not supported...") + MESSAGE(STATUS " Module loading not supported.") ENDIF(HAVE_DLFCN_H) ######################################################################## +# Setup defines for interface address discovery +######################################################################## +MESSAGE(STATUS "Configuring interface address discovery...") + +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(ifaddrs.h HAVE_IFADDRS_H) +CHECK_INCLUDE_FILE_CXX(winsock2.h HAVE_WINSOCK2_H) + +IF(HAVE_IFADDRS_H) + MESSAGE(STATUS " Interface address discovery supported through getifaddrs.") + ADD_DEFINITIONS(-DHAVE_IFADDRS_H) +ELSEIF(HAVE_WINSOCK2_H) + MESSAGE(STATUS " Interface address discovery supported through SIO_GET_INTERFACE_LIST.") + ADD_DEFINITIONS(-DHAVE_WINSOCK2_H) +ELSE(HAVE_IFADDRS_H) + MESSAGE(STATUS " Interface address discovery not supported.") +ENDIF(HAVE_IFADDRS_H) + +######################################################################## # Setup libuhd library ######################################################################## ADD_LIBRARY(uhd SHARED ${libuhd_sources}) diff --git a/host/lib/device.cpp b/host/lib/device.cpp index cd8a01ab4..27a365d34 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -16,8 +16,9 @@ // #include <uhd/device.hpp> -#include <uhd/dict.hpp> -#include <uhd/utils.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> #include <boost/weak_ptr.hpp> @@ -46,7 +47,7 @@ static size_t hash_device_addr( //combine the hashes of sorted keys/value pairs size_t hash = 0; - BOOST_FOREACH(std::string key, keys){ + BOOST_FOREACH(const std::string &key, keys){ boost::hash_combine(hash, key); boost::hash_combine(hash, dev_addr[key]); } @@ -56,26 +57,26 @@ static size_t hash_device_addr( /*********************************************************************** * Registration **********************************************************************/ -typedef boost::tuple<device::discover_t, device::make_t> dev_fcn_reg_t; +typedef boost::tuple<device::find_t, device::make_t> dev_fcn_reg_t; // instantiate the device function registry container -STATIC_INSTANCE(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs) +UHD_SINGLETON_FCN(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs) void device::register_device( - const discover_t &discover, + const find_t &find, const make_t &make ){ //std::cout << "registering device" << std::endl; - get_dev_fcn_regs().push_back(dev_fcn_reg_t(discover, make)); + get_dev_fcn_regs().push_back(dev_fcn_reg_t(find, make)); } /*********************************************************************** * Discover **********************************************************************/ -device_addrs_t device::discover(const device_addr_t &hint){ +device_addrs_t device::find(const device_addr_t &hint){ device_addrs_t device_addrs; - BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){ device_addrs_t discovered_addrs = fcn.get<0>()(hint); device_addrs.insert( device_addrs.begin(), @@ -94,11 +95,11 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t; std::vector<dev_addr_make_t> dev_addr_makers; - BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){ BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){ //copy keys that were in hint but not in dev_addr //this way, we can pass additional transport arguments - BOOST_FOREACH(std::string key, hint.get_keys()){ + BOOST_FOREACH(const std::string &key, hint.get_keys()){ if (not dev_addr.has_key(key)) dev_addr[key] = hint[key]; } //append the discovered address and its factory function @@ -109,14 +110,14 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ //check that we found any devices if (dev_addr_makers.size() == 0){ throw std::runtime_error(str( - boost::format("No devices found for ----->\n%s") % device_addr::to_string(hint) + boost::format("No devices found for ----->\n%s") % hint.to_string() )); } //check that the which index is valid if (dev_addr_makers.size() <= which){ throw std::runtime_error(str( - boost::format("No device at index %d for ----->\n%s") % which % device_addr::to_string(hint) + boost::format("No device at index %d for ----->\n%s") % which % hint.to_string() )); } @@ -136,7 +137,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ return hash_to_device[dev_hash].lock(); } //create and register a new device - catch(const std::assert_error &){ + catch(const uhd::assert_error &){ device::sptr dev = maker(dev_addr); hash_to_device[dev_hash] = dev; return dev; diff --git a/host/lib/device_addr.cpp b/host/lib/device_addr.cpp deleted file mode 100644 index d26bb4b9d..000000000 --- a/host/lib/device_addr.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/device_addr.hpp> -#include <sstream> -#include <cstring> -#include <stdexcept> -#include <boost/format.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/foreach.hpp> - -//----------------------- u2 mac addr wrapper ------------------------// -uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){ - std::string mac_addr_str = (mac_addr_str_ == "")? "ff:ff:ff:ff:ff:ff" : mac_addr_str_; - - //ether_aton_r(str.c_str(), &mac_addr); - boost::uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB - - try{ - //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx - //the IAB above will fill in for the shorter pattern - if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17) - throw std::runtime_error("expected exactly 5 or 17 characters"); - - //split the mac addr hex string at the colons - std::vector<std::string> hex_strs; - boost::split(hex_strs, mac_addr_str, boost::is_any_of(":")); - for (size_t i = 0; i < hex_strs.size(); i++){ - int hex_num; - std::istringstream iss(hex_strs[i]); - iss >> std::hex >> hex_num; - p[i] = boost::uint8_t(hex_num); - } - - } - catch(std::exception const& e){ - throw std::runtime_error(str( - boost::format("Invalid mac address: %s\n\t%s") % mac_addr_str % e.what() - )); - } - - memcpy(&mac_addr, p, sizeof(mac_addr)); -} - -std::string uhd::mac_addr_t::to_string(void) const{ - //ether_ntoa_r(&mac_addr, addr_buf); - const boost::uint8_t *p = reinterpret_cast<const boost::uint8_t *>(&mac_addr); - return str( - boost::format("%02x:%02x:%02x:%02x:%02x:%02x") - % int(p[0]) % int(p[1]) % int(p[2]) - % int(p[3]) % int(p[4]) % int(p[5]) - ); -} - -std::ostream& operator<<(std::ostream &os, const uhd::mac_addr_t &x){ - os << x.to_string(); - return os; -} - -//----------------------- usrp device_addr_t wrapper -------------------------// -std::string uhd::device_addr::to_string(const uhd::device_addr_t &device_addr){ - std::stringstream ss; - BOOST_FOREACH(std::string key, device_addr.get_keys()){ - ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; - } - return ss.str(); -} - -std::ostream& operator<<(std::ostream &os, const uhd::device_addr_t &device_addr){ - os << uhd::device_addr::to_string(device_addr); - return os; -} diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index 7dd1547cb..daf629f0b 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -15,9 +15,9 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/gain_handler.hpp> -#include <uhd/utils.hpp> -#include <uhd/types.hpp> +#include <uhd/utils/gain_handler.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/ranges.hpp> #include <uhd/props.hpp> #include <boost/assign/list_of.hpp> #include <boost/foreach.hpp> @@ -47,7 +47,7 @@ private: is_equal_t _is_equal; prop_names_t get_gain_names(void); - gain_t get_overall_gain_val(void); + float get_overall_gain_val(void); gain_range_t get_overall_gain_range(void); template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){ return _link[named_prop_t(prop, name)].as<T>(); @@ -90,21 +90,21 @@ prop_names_t gain_handler_impl::get_gain_names(void){ return _link[_props.names].as<prop_names_t>(); } -gain_t gain_handler_impl::get_overall_gain_val(void){ - gain_t gain_val = 0; +float gain_handler_impl::get_overall_gain_val(void){ + float gain_val = 0; BOOST_FOREACH(std::string name, get_gain_names()){ - gain_val += get_named_prop<gain_t>(_props.value, name); + gain_val += get_named_prop<float>(_props.value, name); } return gain_val; } gain_range_t gain_handler_impl::get_overall_gain_range(void){ - gain_t gain_min = 0, gain_max = 0, gain_step = 0; + float gain_min = 0, gain_max = 0, gain_step = 0; BOOST_FOREACH(std::string name, get_gain_names()){ - gain_range_t gain_tmp = get_named_prop<gain_range_t>(_props.range, name); - gain_min += gain_tmp.min; - gain_max += gain_tmp.max; - gain_step = std::max(gain_step, gain_tmp.step); + gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name); + gain_min += floatmp.min; + gain_max += floatmp.max; + gain_step = std::max(gain_step, floatmp.step); } return gain_range_t(gain_min, gain_max, gain_step); } @@ -145,7 +145,7 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) //not a gain value key... dont handle if (not _is_equal(key, _props.value)) return false; - gain_t gain_val = val.as<gain_t>(); + float gain_val = val.as<float>(); //not a wildcard... dont handle (but check name and range) if (name != ""){ @@ -164,7 +164,7 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name); //clip g to be within the allowed range - gain_t g = std::min(std::max(gain_val, gain.min), gain.max); + float g = std::min(std::max(gain_val, gain.min), gain.max); //set g to be a multiple of the step size g -= std::fmod(g, gain.step); //set g to be the new gain diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp index 700afcd3f..babff1ca5 100644 --- a/host/lib/load_modules.cpp +++ b/host/lib/load_modules.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/static.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/algorithm/string.hpp> @@ -40,8 +40,8 @@ static void load_module(const std::string &file_name){ } } -#elif HAVE_WINBASE_H -#include <Winbase.h> +#elif HAVE_WINDOWS_H +#include <windows.h> static void load_module(const std::string &file_name){ if (LoadLibrary(file_name.c_str()) == NULL){ @@ -101,7 +101,7 @@ static void load_path(const fs::path &path){ * Load all the modules given by the module path enviroment variable. * The path variable may be several paths split by path separators. */ -STATIC_BLOCK(load_modules){ +UHD_STATIC_BLOCK(load_modules){ //get the environment variable module path char *env_module_path = std::getenv("UHD_MODULE_PATH"); if (env_module_path == NULL) return; diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index ba1966e0d..25beb45a9 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -16,11 +16,9 @@ // #include <uhd/simple_device.hpp> -#include <uhd/device.hpp> -#include <uhd/utils.hpp> +#include <uhd/utils/tune_helper.hpp> +#include <uhd/utils/assert.hpp> #include <uhd/props.hpp> -#include <uhd/types.hpp> -#include <boost/algorithm/string.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> #include <stdexcept> @@ -28,89 +26,8 @@ using namespace uhd; /*********************************************************************** - * Tune Helper Function - **********************************************************************/ -static tune_result_t tune( - double target_freq, - double lo_offset, - wax::obj subdev, - wax::obj dxc, - bool is_tx -){ - wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; - bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>(); - bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>(); - wax::obj dxc_freq_proxy = dxc[std::string("freq")]; - double dxc_sample_rate = dxc[std::string("rate")].as<double>(); - - // Ask the d'board to tune as closely as it can to target_freq+lo_offset - double target_inter_freq = target_freq + lo_offset; - subdev_freq_proxy = target_inter_freq; - double actual_inter_freq = subdev_freq_proxy.as<double>(); - - // Calculate the DDC setting that will downconvert the baseband from the - // daughterboard to our target frequency. - double delta_freq = target_freq - actual_inter_freq; - double delta_sign = std::signum(delta_freq); - delta_freq *= delta_sign; - delta_freq = fmod(delta_freq, dxc_sample_rate); - bool inverted = delta_freq > dxc_sample_rate/2.0; - double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); - target_dxc_freq *= delta_sign; - - // If the spectrum is inverted, and the daughterboard doesn't do - // quadrature downconversion, we can fix the inversion by flipping the - // sign of the dxc_freq... (This only happens using the basic_rx board) - if (subdev_spectrum_inverted){ - inverted = not inverted; - } - if (inverted and not subdev_quadrature){ - target_dxc_freq *= -1.0; - inverted = not inverted; - } - // down conversion versus up conversion, fight! - // your mother is ugly and your going down... - target_dxc_freq *= (is_tx)? -1.0 : +1.0; - - dxc_freq_proxy = target_dxc_freq; - double actual_dxc_freq = dxc_freq_proxy.as<double>(); - - //return some kind of tune result tuple/struct - tune_result_t tune_result; - tune_result.target_inter_freq = target_inter_freq; - tune_result.actual_inter_freq = actual_inter_freq; - tune_result.target_dxc_freq = target_dxc_freq; - tune_result.actual_dxc_freq = actual_dxc_freq; - tune_result.spectrum_inverted = inverted; - return tune_result; -} - -/*********************************************************************** * Helper Functions **********************************************************************/ -static std::string trim(const std::string &in){ - return boost::algorithm::trim_copy(in); -} - -device_addr_t args_to_device_addr(const std::string &args){ - device_addr_t addr; - - //split the args at the semi-colons - std::vector<std::string> pairs; - boost::split(pairs, args, boost::is_any_of(";")); - BOOST_FOREACH(std::string pair, pairs){ - if (trim(pair) == "") continue; - - //split the key value pairs at the equals - std::vector<std::string> key_val; - boost::split(key_val, pair, boost::is_any_of("=")); - if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); - addr[trim(key_val[0])] = trim(key_val[1]); - } - - return addr; -} - static std::vector<double> get_xx_rates(wax::obj decerps, wax::obj rate){ std::vector<double> rates; BOOST_FOREACH(size_t decerp, decerps.as<std::vector<size_t> >()){ @@ -154,42 +71,42 @@ public: } /******************************************************************* - * Streaming + * Timing ******************************************************************/ - void set_streaming(bool enb){ - _rx_ddc[std::string("enabled")] = enb; + void set_time_now(const time_spec_t &time_spec){ + _mboard[MBOARD_PROP_TIME_NOW] = time_spec; } - bool get_streaming(void){ - return _rx_ddc[std::string("enabled")].as<bool>(); + void set_time_next_pps(const time_spec_t &time_spec){ + _mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + + /******************************************************************* + * Streaming + ******************************************************************/ + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + _rx_ddc[std::string("stream_cmd")] = stream_cmd; } /******************************************************************* * RX methods ******************************************************************/ void set_rx_rate(double rate){ - double samp_rate = _rx_ddc[std::string("rate")].as<double>(); + double samp_rate = _rx_ddc[std::string("if_rate")].as<double>(); assert_has(get_rx_rates(), rate, "simple device rx rate"); _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); } double get_rx_rate(void){ - double samp_rate = _rx_ddc[std::string("rate")].as<double>(); - size_t decim = _rx_ddc[std::string("decim")].as<size_t>(); - return samp_rate/decim; + return _rx_ddc[std::string("bb_rate")].as<double>(); } std::vector<double> get_rx_rates(void){ - return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); + return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("if_rate")]); } tune_result_t set_rx_freq(double target_freq){ - double lo_offset = 0.0; - //if the local oscillator will be in the passband, use an offset - if (_rx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ - lo_offset = get_rx_rate()*2.0; - } - return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); + return tune_rx_subdev_and_ddc(_rx_subdev, _rx_ddc, target_freq); } freq_range_t get_rx_freq_range(void){ @@ -201,7 +118,7 @@ public: } float get_rx_gain(void){ - return _rx_subdev[SUBDEV_PROP_GAIN].as<gain_t>(); + return _rx_subdev[SUBDEV_PROP_GAIN].as<float>(); } gain_range_t get_rx_gain_range(void){ @@ -224,28 +141,21 @@ public: * TX methods ******************************************************************/ void set_tx_rate(double rate){ - double samp_rate = _tx_duc[std::string("rate")].as<double>(); + double samp_rate = _tx_duc[std::string("if_rate")].as<double>(); assert_has(get_tx_rates(), rate, "simple device tx rate"); _tx_duc[std::string("interp")] = size_t(samp_rate/rate); } double get_tx_rate(void){ - double samp_rate = _tx_duc[std::string("rate")].as<double>(); - size_t interp = _tx_duc[std::string("interp")].as<size_t>(); - return samp_rate/interp; + return _tx_duc[std::string("bb_rate")].as<double>(); } std::vector<double> get_tx_rates(void){ - return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); + return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("if_rate")]); } tune_result_t set_tx_freq(double target_freq){ - double lo_offset = 0.0; - //if the local oscillator will be in the passband, use an offset - if (_tx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ - lo_offset = get_tx_rate()*2.0; - } - return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); + return tune_tx_subdev_and_duc(_tx_subdev, _tx_duc, target_freq); } freq_range_t get_tx_freq_range(void){ @@ -257,7 +167,7 @@ public: } float get_tx_gain(void){ - return _tx_subdev[SUBDEV_PROP_GAIN].as<gain_t>(); + return _tx_subdev[SUBDEV_PROP_GAIN].as<float>(); } gain_range_t get_tx_gain_range(void){ @@ -289,5 +199,5 @@ private: * The Make Function **********************************************************************/ simple_device::sptr simple_device::make(const std::string &args){ - return sptr(new simple_device_impl(args_to_device_addr(args))); + return sptr(new simple_device_impl(device_addr_t::from_args_str(args))); } diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp deleted file mode 100644 index 210010394..000000000 --- a/host/lib/time_spec.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/time_spec.hpp> - -using namespace uhd; - -time_spec_t::time_spec_t(void){ - secs = ~0; - ticks = ~0; -} - -time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){ - secs = new_secs; - ticks = new_ticks; -} - -static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); -static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second()); - -time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ - boost::posix_time::time_duration td = time - epoch; - secs = boost::uint32_t(td.total_seconds()); - double time_ticks_per_device_ticks = time_tick_rate/tick_rate; - ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); -} diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py new file mode 100755 index 000000000..918de3ad7 --- /dev/null +++ b/host/lib/transport/gen_vrt.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +""" +The vrt packer/unpacker code generator: + +This script will generate the pack and unpack routines that convert +metatdata into vrt headers and vrt headers into metadata. + +The generated code infers jump tables to speed-up the parsing time. +""" + +TMPL_TEXT = """ +#import time + +######################################################################## +## setup predicates +######################################################################## +#set $sid_p = 0b00001 +#set $cid_p = 0b00010 +#set $tsi_p = 0b00100 +#set $tsf_p = 0b01000 +#set $tlr_p = 0b10000 + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#include <uhd/transport/vrt.hpp> +\#include <boost/asio.hpp> //endianness conversion +\#include <stdexcept> + +using namespace uhd; +using namespace uhd::transport; + +void vrt::pack( + const tx_metadata_t &metadata, //input + boost::uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t &num_packet_words32, //output + size_t packet_count //input +){ + boost::uint32_t vrt_hdr_flags; + + boost::uint8_t pred = 0; + if (metadata.has_stream_id) pred |= $hex($sid_p); + if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $num_header_words = 1 + #set $flags = 0 + ########## Stream ID ########## + #if $pred & $sid_p + header_buff[$num_header_words] = htonl(metadata.stream_id); + #set $num_header_words += 1 + #set $flags |= (0x1 << 28); + #end if + ########## Class ID ########## + #if $pred & $cid_p + header_buff[$num_header_words] = htonl(0); + #set $num_header_words += 1 + header_buff[$num_header_words] = htonl(0); + #set $num_header_words += 1 + #set $flags |= (0x1 << 27); + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + header_buff[$num_header_words] = htonl(metadata.time_spec.secs); + #set $num_header_words += 1 + #set $flags |= (0x3 << 22); + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + header_buff[$num_header_words] = htonl(0); + #set $num_header_words += 1 + header_buff[$num_header_words] = htonl(metadata.time_spec.ticks); + #set $num_header_words += 1 + #set $flags |= (0x1 << 20); + #end if + ########## Trailer ########## + #if $pred & $tlr_p + #set $flags |= (0x1 << 26); + #set $num_trailer_words = 1; + #else + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + num_header_words32 = $num_header_words; + num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32; + vrt_hdr_flags = $hex($flags); + break; + #end for + } + + //set the burst flags + if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25); + if (metadata.end_of_burst) vrt_hdr_flags |= $hex(0x1 << 24); + + //fill in complete header word + header_buff[0] = htonl(vrt_hdr_flags | + ((packet_count & 0xf) << 16) | + (num_packet_words32 & 0xffff) + ); +} + +void vrt::unpack( + rx_metadata_t &metadata, //output + const boost::uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t num_packet_words32, //input + size_t &packet_count //output +){ + //clear the metadata + metadata = rx_metadata_t(); + + //extract vrt header + boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]); + size_t packet_words32 = vrt_hdr_word & 0xffff; + packet_count = (vrt_hdr_word >> 16) & 0xf; + + //failure cases + if (packet_words32 == 0 or num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); + if (vrt_hdr_word & (0x7 << 29)) + throw std::runtime_error("unsupported vrt packet type"); + + boost::uint8_t pred = 0; + if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); + if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); + if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); + if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); + if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); + + switch(pred){ + #for $pred in range(2**5) + case $pred: + #set $set_has_time_spec = False + #set $num_header_words = 1 + ########## Stream ID ########## + #if $pred & $sid_p + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[$num_header_words]); + #set $num_header_words += 1 + #end if + ########## Class ID ########## + #if $pred & $cid_p + #set $num_header_words += 1 + #set $num_header_words += 1 + #end if + ########## Integer Time ########## + #if $pred & $tsi_p + metadata.has_time_spec = true; + #set $set_has_time_spec = True + metadata.time_spec.secs = ntohl(header_buff[$num_header_words]); + #set $num_header_words += 1 + #end if + ########## Fractional Time ########## + #if $pred & $tsf_p + #if not $set_has_time_spec + metadata.has_time_spec = true; + #set $set_has_time_spec = True + #end if + #set $num_header_words += 1 + metadata.time_spec.ticks = ntohl(header_buff[$num_header_words]); + #set $num_header_words += 1 + #end if + ########## Trailer ########## + #if $pred & $tlr_p + #set $num_trailer_words = 1; + #else + #set $num_trailer_words = 0; + #end if + ########## Variables ########## + num_header_words32 = $num_header_words; + num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); + break; + #end for + } +} +""" + +from Cheetah import Template +def parse_str(_tmpl_text, **kwargs): return str(Template.Template(_tmpl_text, kwargs)) + +if __name__ == '__main__': + from Cheetah import Template + print parse_str(TMPL_TEXT, file=__file__) diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp new file mode 100644 index 000000000..5c8c8a176 --- /dev/null +++ b/host/lib/transport/if_addrs.cpp @@ -0,0 +1,109 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/transport/if_addrs.hpp> +#include <boost/asio/ip/address_v4.hpp> +#include <boost/cstdint.hpp> +#include <iostream> + +uhd::transport::if_addrs_t::if_addrs_t(void){ + /* NOP */ +} + +/*********************************************************************** + * Interface address discovery through ifaddrs api + **********************************************************************/ +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> + +static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){ + return boost::asio::ip::address_v4(ntohl( + reinterpret_cast<sockaddr_in*>(addr)->sin_addr.s_addr + )); +} + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ + std::vector<if_addrs_t> if_addrs; + struct ifaddrs *ifap; + if (getifaddrs(&ifap) == 0){ + for (struct ifaddrs *iter = ifap; iter != NULL; iter = iter->ifa_next){ + //ensure that the entries are valid + if (iter->ifa_addr->sa_family != AF_INET) continue; + if (iter->ifa_netmask->sa_family != AF_INET) continue; + if (iter->ifa_broadaddr->sa_family != AF_INET) continue; + + //append a new set of interface addresses + if_addrs_t if_addr; + if_addr.inet = sockaddr_to_ip_addr(iter->ifa_addr).to_string(); + if_addr.mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_string(); + if_addr.bcast = sockaddr_to_ip_addr(iter->ifa_broadaddr).to_string(); + if_addrs.push_back(if_addr); + } + freeifaddrs(ifap); + } + return if_addrs; +} + +/*********************************************************************** + * Interface address discovery through windows api (TODO) + **********************************************************************/ +#elif HAVE_WINSOCK2_H +#include <winsock2.h> + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ + std::vector<if_addrs_t> if_addrs; + SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); + if (sd == SOCKET_ERROR) { + std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << + std::endl; return if_addrs; + } + + INTERFACE_INFO InterfaceList[20]; + unsigned long nBytesReturned; + if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, + sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { + std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << + std::endl; + return if_addrs; + } + + int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); + for (int i = 0; i < nNumInterfaces; ++i) { + boost::uint32_t iiAddress = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiAddress).sin_addr.s_addr); + boost::uint32_t iiNetmask = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiNetmask).sin_addr.s_addr); + boost::uint32_t iiBroadcastAddress = (iiAddress & iiNetmask) | ~iiNetmask; + + if_addrs_t if_addr; + if_addr.inet = boost::asio::ip::address_v4(iiAddress).to_string(); + if_addr.mask = boost::asio::ip::address_v4(iiNetmask).to_string(); + if_addr.bcast = boost::asio::ip::address_v4(iiBroadcastAddress).to_string(); + if_addrs.push_back(if_addr); + } + + return if_addrs; +} + +/*********************************************************************** + * Interface address discovery not included + **********************************************************************/ +#else /* HAVE_IFADDRS_H */ + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ + return std::vector<if_addrs_t>(); +} + +#endif /* HAVE_IFADDRS_H */ diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 3c8ecb70d..f339127ad 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -16,6 +16,7 @@ // #include <uhd/transport/udp_simple.hpp> +#include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/format.hpp> #include <iostream> diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 219ae8720..1fc8ce14a 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -17,6 +17,7 @@ #include <uhd/transport/udp_zero_copy.hpp> #include <boost/cstdint.hpp> +#include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/format.hpp> #include <iostream> @@ -115,7 +116,7 @@ smart_buffer::sptr udp_zero_copy_impl::recv(void){ //implement timeout through polling and sleeping boost::asio::deadline_timer timer(_socket->get_io_service()); - timer.expires_from_now(boost::posix_time::milliseconds(50)); + timer.expires_from_now(boost::posix_time::milliseconds(100)); while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index a06b5bf21..bebca5db9 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -1,19 +1,9 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// + + + +/*********************************************************************** + * This file was generated by ./gen_vrt.py on Fri Mar 26 15:33:00 2010 + **********************************************************************/ #include <uhd/transport/vrt.hpp> #include <boost/asio.hpp> //endianness conversion @@ -30,26 +20,274 @@ void vrt::pack( size_t &num_packet_words32, //output size_t packet_count //input ){ - boost::uint32_t vrt_hdr_flags = 0; - num_header_words32 = 1; + boost::uint32_t vrt_hdr_flags; - //load the vrt header and flags - if(metadata.has_stream_id){ - vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier - header_buff[num_header_words32++] = htonl(metadata.stream_id); - } + boost::uint8_t pred = 0; + if (metadata.has_stream_id) pred |= 0x1; + if (metadata.has_time_spec) pred |= 0xc; - if(metadata.has_time_spec){ - vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp - header_buff[num_header_words32++] = htonl(metadata.time_spec.secs); - header_buff[num_header_words32++] = htonl(metadata.time_spec.ticks); - header_buff[num_header_words32++] = 0; //unused part of fractional seconds + switch(pred){ + case 0: + num_header_words32 = 1; + num_packet_words32 = 1 + num_payload_words32; + vrt_hdr_flags = 0x0; + break; + case 1: + header_buff[1] = htonl(metadata.stream_id); + num_header_words32 = 2; + num_packet_words32 = 2 + num_payload_words32; + vrt_hdr_flags = 0x10000000; + break; + case 2: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + num_header_words32 = 3; + num_packet_words32 = 3 + num_payload_words32; + vrt_hdr_flags = 0x8000000; + break; + case 3: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + num_header_words32 = 4; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0x18000000; + break; + case 4: + header_buff[1] = htonl(metadata.time_spec.secs); + num_header_words32 = 2; + num_packet_words32 = 2 + num_payload_words32; + vrt_hdr_flags = 0xc00000; + break; + case 5: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(metadata.time_spec.secs); + num_header_words32 = 3; + num_packet_words32 = 3 + num_payload_words32; + vrt_hdr_flags = 0x10c00000; + break; + case 6: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.secs); + num_header_words32 = 4; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0x8c00000; + break; + case 7: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.secs); + num_header_words32 = 5; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x18c00000; + break; + case 8: + header_buff[1] = htonl(0); + header_buff[2] = htonl(metadata.time_spec.ticks); + num_header_words32 = 3; + num_packet_words32 = 3 + num_payload_words32; + vrt_hdr_flags = 0x100000; + break; + case 9: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.ticks); + num_header_words32 = 4; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0x10100000; + break; + case 10: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.ticks); + num_header_words32 = 5; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x8100000; + break; + case 11: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(0); + header_buff[5] = htonl(metadata.time_spec.ticks); + num_header_words32 = 6; + num_packet_words32 = 6 + num_payload_words32; + vrt_hdr_flags = 0x18100000; + break; + case 12: + header_buff[1] = htonl(metadata.time_spec.secs); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.ticks); + num_header_words32 = 4; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0xd00000; + break; + case 13: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(metadata.time_spec.secs); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.ticks); + num_header_words32 = 5; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x10d00000; + break; + case 14: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.secs); + header_buff[4] = htonl(0); + header_buff[5] = htonl(metadata.time_spec.ticks); + num_header_words32 = 6; + num_packet_words32 = 6 + num_payload_words32; + vrt_hdr_flags = 0x8d00000; + break; + case 15: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.secs); + header_buff[5] = htonl(0); + header_buff[6] = htonl(metadata.time_spec.ticks); + num_header_words32 = 7; + num_packet_words32 = 7 + num_payload_words32; + vrt_hdr_flags = 0x18d00000; + break; + case 16: + num_header_words32 = 1; + num_packet_words32 = 2 + num_payload_words32; + vrt_hdr_flags = 0x4000000; + break; + case 17: + header_buff[1] = htonl(metadata.stream_id); + num_header_words32 = 2; + num_packet_words32 = 3 + num_payload_words32; + vrt_hdr_flags = 0x14000000; + break; + case 18: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + num_header_words32 = 3; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0xc000000; + break; + case 19: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + num_header_words32 = 4; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x1c000000; + break; + case 20: + header_buff[1] = htonl(metadata.time_spec.secs); + num_header_words32 = 2; + num_packet_words32 = 3 + num_payload_words32; + vrt_hdr_flags = 0x4c00000; + break; + case 21: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(metadata.time_spec.secs); + num_header_words32 = 3; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0x14c00000; + break; + case 22: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.secs); + num_header_words32 = 4; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0xcc00000; + break; + case 23: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.secs); + num_header_words32 = 5; + num_packet_words32 = 6 + num_payload_words32; + vrt_hdr_flags = 0x1cc00000; + break; + case 24: + header_buff[1] = htonl(0); + header_buff[2] = htonl(metadata.time_spec.ticks); + num_header_words32 = 3; + num_packet_words32 = 4 + num_payload_words32; + vrt_hdr_flags = 0x4100000; + break; + case 25: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.ticks); + num_header_words32 = 4; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x14100000; + break; + case 26: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.ticks); + num_header_words32 = 5; + num_packet_words32 = 6 + num_payload_words32; + vrt_hdr_flags = 0xc100000; + break; + case 27: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(0); + header_buff[5] = htonl(metadata.time_spec.ticks); + num_header_words32 = 6; + num_packet_words32 = 7 + num_payload_words32; + vrt_hdr_flags = 0x1c100000; + break; + case 28: + header_buff[1] = htonl(metadata.time_spec.secs); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.ticks); + num_header_words32 = 4; + num_packet_words32 = 5 + num_payload_words32; + vrt_hdr_flags = 0x4d00000; + break; + case 29: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(metadata.time_spec.secs); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.ticks); + num_header_words32 = 5; + num_packet_words32 = 6 + num_payload_words32; + vrt_hdr_flags = 0x14d00000; + break; + case 30: + header_buff[1] = htonl(0); + header_buff[2] = htonl(0); + header_buff[3] = htonl(metadata.time_spec.secs); + header_buff[4] = htonl(0); + header_buff[5] = htonl(metadata.time_spec.ticks); + num_header_words32 = 6; + num_packet_words32 = 7 + num_payload_words32; + vrt_hdr_flags = 0xcd00000; + break; + case 31: + header_buff[1] = htonl(metadata.stream_id); + header_buff[2] = htonl(0); + header_buff[3] = htonl(0); + header_buff[4] = htonl(metadata.time_spec.secs); + header_buff[5] = htonl(0); + header_buff[6] = htonl(metadata.time_spec.ticks); + num_header_words32 = 7; + num_packet_words32 = 8 + num_payload_words32; + vrt_hdr_flags = 0x1cd00000; + break; } - vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; - vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; - - num_packet_words32 = num_header_words32 + num_payload_words32; + //set the burst flags + if (metadata.start_of_burst) vrt_hdr_flags |= 0x2000000; + if (metadata.end_of_burst) vrt_hdr_flags |= 0x1000000; //fill in complete header word header_buff[0] = htonl(vrt_hdr_flags | @@ -80,30 +318,230 @@ void vrt::unpack( if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); - //parse the header flags - num_header_words32 = 1; - - if (vrt_hdr_word & (0x1 << 28)){ //stream id - metadata.has_stream_id = true; - metadata.stream_id = ntohl(header_buff[num_header_words32++]); - } - - if (vrt_hdr_word & (0x1 << 27)){ //class id (we dont use) - num_header_words32 += 2; - } - - if (vrt_hdr_word & (0x3 << 22)){ //integer time - metadata.has_time_spec = true; - metadata.time_spec.secs = ntohl(header_buff[num_header_words32++]); - } + boost::uint8_t pred = 0; + if(vrt_hdr_word & 0x10000000) pred |= 0x1; + if(vrt_hdr_word & 0x8000000) pred |= 0x2; + if(vrt_hdr_word & 0xc00000) pred |= 0x4; + if(vrt_hdr_word & 0x300000) pred |= 0x8; + if(vrt_hdr_word & 0x4000000) pred |= 0x10; - if (vrt_hdr_word & (0x3 << 20)){ //fractional time - metadata.has_time_spec = true; - metadata.time_spec.ticks = ntohl(header_buff[num_header_words32++]); - num_header_words32++; //unused part of fractional seconds + switch(pred){ + case 0: + num_header_words32 = 1; + num_payload_words32 = packet_words32 - 1; + break; + case 1: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + num_header_words32 = 2; + num_payload_words32 = packet_words32 - 2; + break; + case 2: + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 3; + break; + case 3: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 4; + break; + case 4: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[1]); + num_header_words32 = 2; + num_payload_words32 = packet_words32 - 2; + break; + case 5: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[2]); + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 3; + break; + case 6: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 4; + break; + case 7: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 5; + break; + case 8: + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[2]); + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 3; + break; + case 9: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 4; + break; + case 10: + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 5; + break; + case 11: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[5]); + num_header_words32 = 6; + num_payload_words32 = packet_words32 - 6; + break; + case 12: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[1]); + metadata.time_spec.ticks = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 4; + break; + case 13: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[2]); + metadata.time_spec.ticks = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 5; + break; + case 14: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[3]); + metadata.time_spec.ticks = ntohl(header_buff[5]); + num_header_words32 = 6; + num_payload_words32 = packet_words32 - 6; + break; + case 15: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[4]); + metadata.time_spec.ticks = ntohl(header_buff[6]); + num_header_words32 = 7; + num_payload_words32 = packet_words32 - 7; + break; + case 16: + num_header_words32 = 1; + num_payload_words32 = packet_words32 - 2; + break; + case 17: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + num_header_words32 = 2; + num_payload_words32 = packet_words32 - 3; + break; + case 18: + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 4; + break; + case 19: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 5; + break; + case 20: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[1]); + num_header_words32 = 2; + num_payload_words32 = packet_words32 - 3; + break; + case 21: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[2]); + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 4; + break; + case 22: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 5; + break; + case 23: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 6; + break; + case 24: + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[2]); + num_header_words32 = 3; + num_payload_words32 = packet_words32 - 4; + break; + case 25: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 5; + break; + case 26: + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 6; + break; + case 27: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[5]); + num_header_words32 = 6; + num_payload_words32 = packet_words32 - 7; + break; + case 28: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[1]); + metadata.time_spec.ticks = ntohl(header_buff[3]); + num_header_words32 = 4; + num_payload_words32 = packet_words32 - 5; + break; + case 29: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[2]); + metadata.time_spec.ticks = ntohl(header_buff[4]); + num_header_words32 = 5; + num_payload_words32 = packet_words32 - 6; + break; + case 30: + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[3]); + metadata.time_spec.ticks = ntohl(header_buff[5]); + num_header_words32 = 6; + num_payload_words32 = packet_words32 - 7; + break; + case 31: + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[1]); + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[4]); + metadata.time_spec.ticks = ntohl(header_buff[6]); + num_header_words32 = 7; + num_payload_words32 = packet_words32 - 8; + break; } - - size_t num_trailer_words32 = (vrt_hdr_word & (0x1 << 26))? 1 : 0; - - num_payload_words32 = packet_words32 - num_header_words32 - num_trailer_words32; } + diff --git a/host/lib/tune_helper.cpp b/host/lib/tune_helper.cpp new file mode 100644 index 000000000..1e5c4cd0d --- /dev/null +++ b/host/lib/tune_helper.cpp @@ -0,0 +1,125 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/tune_helper.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/props.hpp> +#include <cmath> + +using namespace uhd; + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune_xx_subdev_and_dxc( + bool is_tx, + wax::obj subdev, wax::obj dxc, + double target_freq, double lo_offset +){ + wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; + bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>(); + bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>(); + wax::obj dxc_freq_proxy = dxc[std::string("freq")]; + double dxc_sample_rate = dxc[std::string("if_rate")].as<double>(); + + // Ask the d'board to tune as closely as it can to target_freq+lo_offset + double target_inter_freq = target_freq + lo_offset; + subdev_freq_proxy = target_inter_freq; + double actual_inter_freq = subdev_freq_proxy.as<double>(); + + // Calculate the DDC setting that will downconvert the baseband from the + // daughterboard to our target frequency. + double delta_freq = target_freq - actual_inter_freq; + double delta_sign = std::signum(delta_freq); + delta_freq *= delta_sign; + delta_freq = std::fmod(delta_freq, dxc_sample_rate); + bool inverted = delta_freq > dxc_sample_rate/2.0; + double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); + target_dxc_freq *= delta_sign; + + // If the spectrum is inverted, and the daughterboard doesn't do + // quadrature downconversion, we can fix the inversion by flipping the + // sign of the dxc_freq... (This only happens using the basic_rx board) + if (subdev_spectrum_inverted){ + inverted = not inverted; + } + if (inverted and not subdev_quadrature){ + target_dxc_freq *= -1.0; + inverted = not inverted; + } + // down conversion versus up conversion, fight! + // your mother is ugly and your going down... + target_dxc_freq *= (is_tx)? -1.0 : +1.0; + + dxc_freq_proxy = target_dxc_freq; + double actual_dxc_freq = dxc_freq_proxy.as<double>(); + + //return some kind of tune result tuple/struct + tune_result_t tune_result; + tune_result.target_inter_freq = target_inter_freq; + tune_result.actual_inter_freq = actual_inter_freq; + tune_result.target_dxc_freq = target_dxc_freq; + tune_result.actual_dxc_freq = actual_dxc_freq; + tune_result.spectrum_inverted = inverted; + return tune_result; +} + +/*********************************************************************** + * RX Tune + **********************************************************************/ +tune_result_t uhd::tune_rx_subdev_and_ddc( + wax::obj subdev, wax::obj ddc, + double target_freq, double lo_offset +){ + bool is_tx = false; + return tune_xx_subdev_and_dxc(is_tx, subdev, ddc, target_freq, lo_offset); +} + +tune_result_t uhd::tune_rx_subdev_and_ddc( + wax::obj subdev, wax::obj ddc, + double target_freq +){ + double lo_offset = 0.0; + //if the local oscillator will be in the passband, use an offset + if (subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ + lo_offset = 2.0*ddc[std::string("bb_rate")].as<double>(); + } + return tune_rx_subdev_and_ddc(subdev, ddc, target_freq, lo_offset); +} + +/*********************************************************************** + * TX Tune + **********************************************************************/ +tune_result_t uhd::tune_tx_subdev_and_duc( + wax::obj subdev, wax::obj duc, + double target_freq, double lo_offset +){ + bool is_tx = true; + return tune_xx_subdev_and_dxc(is_tx, subdev, duc, target_freq, lo_offset); +} + +tune_result_t uhd::tune_tx_subdev_and_duc( + wax::obj subdev, wax::obj duc, + double target_freq +){ + double lo_offset = 0.0; + //if the local oscillator will be in the passband, use an offset + if (subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ + lo_offset = 2.0*duc[std::string("bb_rate")].as<double>(); + } + return tune_tx_subdev_and_duc(subdev, duc, target_freq, lo_offset); +} diff --git a/host/lib/types.cpp b/host/lib/types.cpp index f8a9a9b36..bf9f8b895 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -15,12 +15,27 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/types.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/tune_result.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/types/time_spec.hpp> +#include <uhd/types/device_addr.hpp> +#include <uhd/types/mac_addr.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/io_type.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/cstdint.hpp> +#include <stdexcept> +#include <complex> using namespace uhd; /*********************************************************************** - * gain range + * ranges **********************************************************************/ gain_range_t::gain_range_t(float min_, float max_, float step_){ min = min_; @@ -28,9 +43,6 @@ gain_range_t::gain_range_t(float min_, float max_, float step_){ step = step_; } -/*********************************************************************** - * freq range - **********************************************************************/ freq_range_t::freq_range_t(double min_, double max_){ min = min_; max = max_; @@ -51,7 +63,185 @@ tune_result_t::tune_result_t(void){ * clock config **********************************************************************/ clock_config_t::clock_config_t(void){ - ref_source = ""; //not a valid setting - pps_source = ""; //not a valid setting - pps_polarity = POLARITY_NEG; + ref_source = REF_INT, + pps_source = PPS_INT, + pps_polarity = PPS_NEG; +} + +/*********************************************************************** + * stream command + **********************************************************************/ +stream_cmd_t::stream_cmd_t(void){ + stream_now = true; + continuous = false; + num_samps = 0; +} + +/*********************************************************************** + * metadata + **********************************************************************/ +rx_metadata_t::rx_metadata_t(void){ + stream_id = 0; + has_stream_id = false; + time_spec = time_spec_t(); + has_time_spec = false; + is_fragment = false; +} + +tx_metadata_t::tx_metadata_t(void){ + stream_id = 0; + has_stream_id = false; + time_spec = time_spec_t(); + has_time_spec = false; + start_of_burst = false; + end_of_burst = false; +} + +/*********************************************************************** + * time spec + **********************************************************************/ +time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){ + secs = new_secs; + ticks = new_ticks; +} + +static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); +static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second()); + +time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ + boost::posix_time::time_duration td = time - epoch; + secs = boost::uint32_t(td.total_seconds()); + double time_ticks_per_device_ticks = time_tick_rate/tick_rate; + ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); +} + +/*********************************************************************** + * device addr + **********************************************************************/ +std::string device_addr_t::to_string(void) const{ + const device_addr_t &device_addr = *this; + std::stringstream ss; + BOOST_FOREACH(std::string key, device_addr.get_keys()){ + ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; + } + return ss.str(); +} + +static const std::string arg_delim = ";"; +static const std::string pair_delim = "="; + +static std::string trim(const std::string &in){ + return boost::algorithm::trim_copy(in); +} + +std::string device_addr_t::to_args_str(void) const{ + std::string args_str; + const device_addr_t &device_addr = *this; + BOOST_FOREACH(const std::string &key, device_addr.get_keys()){ + args_str += key + pair_delim + device_addr[key] + arg_delim; + } + return args_str; +} + +device_addr_t device_addr_t::from_args_str(const std::string &args_str){ + device_addr_t addr; + + //split the args at the semi-colons + std::vector<std::string> pairs; + boost::split(pairs, args_str, boost::is_any_of(arg_delim)); + BOOST_FOREACH(const std::string &pair, pairs){ + if (trim(pair) == "") continue; + + //split the key value pairs at the equals + std::vector<std::string> key_val; + boost::split(key_val, pair, boost::is_any_of(pair_delim)); + if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args_str); + addr[trim(key_val[0])] = trim(key_val[1]); + } + + return addr; +} + +/*********************************************************************** + * mac addr + **********************************************************************/ +mac_addr_t::mac_addr_t(const boost::uint8_t *bytes){ + std::copy(bytes, bytes+hlen, _bytes); +} + +mac_addr_t mac_addr_t::from_bytes(const boost::uint8_t *bytes){ + return mac_addr_t(bytes); +} + +mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ + + boost::uint8_t p[hlen] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB + + try{ + //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx + //the IAB above will fill in for the shorter pattern + if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17) + throw std::runtime_error("expected exactly 5 or 17 characters"); + + //split the mac addr hex string at the colons + std::vector<std::string> hex_strs; + boost::split(hex_strs, mac_addr_str, boost::is_any_of(":")); + for (size_t i = 0; i < hex_strs.size(); i++){ + int hex_num; + std::istringstream iss(hex_strs[i]); + iss >> std::hex >> hex_num; + p[i] = boost::uint8_t(hex_num); + } + + } + catch(std::exception const& e){ + throw std::runtime_error(str( + boost::format("Invalid mac address: %s\n\t%s") % mac_addr_str % e.what() + )); + } + + return from_bytes(p); +} + +const boost::uint8_t *mac_addr_t::to_bytes(void) const{ + return _bytes; +} + +std::string mac_addr_t::to_string(void) const{ + return str( + boost::format("%02x:%02x:%02x:%02x:%02x:%02x") + % int(to_bytes()[0]) % int(to_bytes()[1]) % int(to_bytes()[2]) + % int(to_bytes()[3]) % int(to_bytes()[4]) % int(to_bytes()[5]) + ); +} + +/*********************************************************************** + * otw type + **********************************************************************/ +otw_type_t::otw_type_t(void){ + width = 0; + shift = 0; + byteorder = BO_NATIVE; +} + +/*********************************************************************** + * io type + **********************************************************************/ +static size_t tid_to_size(io_type_t::tid_t tid){ + switch(tid){ + case io_type_t::COMPLEX_FLOAT32: return sizeof(std::complex<float>); + case io_type_t::COMPLEX_INT16: return sizeof(std::complex<boost::int16_t>); + case io_type_t::COMPLEX_INT8: return sizeof(std::complex<boost::int8_t>); + default: throw std::runtime_error("unknown io type tid"); + } +} + +io_type_t::io_type_t(tid_t tid) +: size(tid_to_size(tid)), tid(tid){ + /* NOP */ +} + +io_type_t::io_type_t(size_t size) +: size(size), tid(CUSTOM_TYPE){ + /* NOP */ } diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 82485ae6a..2f29c8e0c 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -15,9 +15,10 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> #include <uhd/props.hpp> -#include <uhd/types.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> @@ -33,26 +34,26 @@ using namespace boost::assign; **********************************************************************/ class basic_rx : public rx_dboard_base{ public: - basic_rx(ctor_args_t const& args, freq_t max_freq); + basic_rx(ctor_args_t const& args, double max_freq); ~basic_rx(void); void rx_get(const wax::obj &key, wax::obj &val); void rx_set(const wax::obj &key, const wax::obj &val); private: - freq_t _max_freq; + double _max_freq; }; class basic_tx : public tx_dboard_base{ public: - basic_tx(ctor_args_t const& args, freq_t max_freq); + basic_tx(ctor_args_t const& args, double max_freq); ~basic_tx(void); void tx_get(const wax::obj &key, wax::obj &val); void tx_set(const wax::obj &key, const wax::obj &val); private: - freq_t _max_freq; + double _max_freq; }; /*********************************************************************** @@ -74,17 +75,17 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){ return dboard_base::sptr(new basic_tx(args, 32e6)); } -STATIC_BLOCK(reg_dboards){ - dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", list_of("")); +UHD_STATIC_BLOCK(reg_dboards){ + dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX"); dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b")); - dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX", list_of("")); + dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX"); dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("ab")("a")("b")); } /*********************************************************************** * Basic and LF RX dboard **********************************************************************/ -basic_rx::basic_rx(ctor_args_t const& args, freq_t max_freq) : rx_dboard_base(args){ +basic_rx::basic_rx(ctor_args_t const& args, double max_freq) : rx_dboard_base(args){ _max_freq = max_freq; // set the gpios to safe values (all inputs) get_interface()->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); @@ -112,7 +113,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - val = gain_t(0); + val = float(0); return; case SUBDEV_PROP_GAIN_RANGE: @@ -124,7 +125,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = freq_t(0); + val = double(0); return; case SUBDEV_PROP_FREQ_RANGE: @@ -163,7 +164,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ switch(key.as<subdev_prop_t>()){ case SUBDEV_PROP_GAIN: - ASSERT_THROW(val.as<gain_t>() == gain_t(0)); + ASSERT_THROW(val.as<float>() == float(0)); return; case SUBDEV_PROP_ANTENNA: @@ -195,7 +196,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ /*********************************************************************** * Basic and LF TX dboard **********************************************************************/ -basic_tx::basic_tx(ctor_args_t const& args, freq_t max_freq) : tx_dboard_base(args){ +basic_tx::basic_tx(ctor_args_t const& args, double max_freq) : tx_dboard_base(args){ _max_freq = max_freq; // set the gpios to safe values (all inputs) get_interface()->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff); @@ -220,7 +221,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - val = gain_t(0); + val = float(0); return; case SUBDEV_PROP_GAIN_RANGE: @@ -232,7 +233,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = freq_t(0); + val = double(0); return; case SUBDEV_PROP_FREQ_RANGE: @@ -271,7 +272,7 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ switch(key.as<subdev_prop_t>()){ case SUBDEV_PROP_GAIN: - ASSERT_THROW(val.as<gain_t>() == gain_t(0)); + ASSERT_THROW(val.as<float>() == float(0)); return; case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp index 6dd41cfd8..09d3bbfd4 100644 --- a/host/lib/usrp/dboard_base.cpp +++ b/host/lib/usrp/dboard_base.cpp @@ -52,15 +52,15 @@ dboard_id_t dboard_base::get_tx_id(void){ * xcvr dboard dboard_base class **********************************************************************/ xcvr_dboard_base::xcvr_dboard_base(ctor_args_t const& args) : dboard_base(args){ - if (get_rx_id() == ID_NONE){ + if (get_rx_id() == dboard_id::NONE){ throw std::runtime_error(str(boost::format( "cannot create xcvr board when the rx id is \"%s\"" - ) % dboard_id::to_string(ID_NONE))); + ) % dboard_id::to_string(dboard_id::NONE))); } - if (get_tx_id() == ID_NONE){ + if (get_tx_id() == dboard_id::NONE){ throw std::runtime_error(str(boost::format( "cannot create xcvr board when the tx id is \"%s\"" - ) % dboard_id::to_string(ID_NONE))); + ) % dboard_id::to_string(dboard_id::NONE))); } } @@ -72,11 +72,11 @@ xcvr_dboard_base::~xcvr_dboard_base(void){ * rx dboard dboard_base class **********************************************************************/ rx_dboard_base::rx_dboard_base(ctor_args_t const& args) : dboard_base(args){ - if (get_tx_id() != ID_NONE){ + if (get_tx_id() != dboard_id::NONE){ throw std::runtime_error(str(boost::format( "cannot create rx board when the tx id is \"%s\"" " -> expected a tx id of \"%s\"" - ) % dboard_id::to_string(get_tx_id()) % dboard_id::to_string(ID_NONE))); + ) % dboard_id::to_string(get_tx_id()) % dboard_id::to_string(dboard_id::NONE))); } } @@ -96,11 +96,11 @@ void rx_dboard_base::tx_set(const wax::obj &, const wax::obj &){ * tx dboard dboard_base class **********************************************************************/ tx_dboard_base::tx_dboard_base(ctor_args_t const& args) : dboard_base(args){ - if (get_rx_id() != ID_NONE){ + if (get_rx_id() != dboard_id::NONE){ throw std::runtime_error(str(boost::format( "cannot create tx board when the rx id is \"%s\"" " -> expected a rx id of \"%s\"" - ) % dboard_id::to_string(get_rx_id()) % dboard_id::to_string(ID_NONE))); + ) % dboard_id::to_string(get_rx_id()) % dboard_id::to_string(dboard_id::NONE))); } } diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 6ca15e98c..424626023 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -16,9 +16,10 @@ // #include <uhd/usrp/dboard_manager.hpp> -#include <uhd/gain_handler.hpp> -#include <uhd/utils.hpp> -#include <uhd/dict.hpp> +#include <uhd/utils/gain_handler.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/dict.hpp> #include <boost/tuple/tuple.hpp> #include <boost/format.hpp> #include <boost/bind.hpp> @@ -35,7 +36,7 @@ typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> a //map a dboard id to a dboard constructor typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t; -STATIC_INSTANCE(id_to_args_map_t, get_id_to_args_map) +UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map) void dboard_manager::register_dboard( dboard_id_t dboard_id, @@ -163,12 +164,12 @@ static args_t get_dboard_args( std::string const& xx_type ){ //special case, its rx and the none id (0xffff) - if (xx_type == "rx" and dboard_id == ID_NONE){ + if (xx_type == "rx" and dboard_id == dboard_id::NONE){ return get_dboard_args(0x0001, xx_type); } //special case, its tx and the none id (0xffff) - if (xx_type == "tx" and dboard_id == ID_NONE){ + if (xx_type == "tx" and dboard_id == dboard_id::NONE){ return get_dboard_args(0x0000, xx_type); } @@ -203,7 +204,7 @@ dboard_manager_impl::dboard_manager_impl( //make xcvr subdevs (make one subdev for both rx and tx dboards) if (rx_dboard_ctor == tx_dboard_ctor){ ASSERT_THROW(rx_subdevs == tx_subdevs); - BOOST_FOREACH(std::string subdev, rx_subdevs){ + BOOST_FOREACH(const std::string &subdev, rx_subdevs){ dboard_base::sptr xcvr_dboard = rx_dboard_ctor( dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id) ); @@ -221,9 +222,9 @@ dboard_manager_impl::dboard_manager_impl( //make tx and rx subdevs (separate subdevs for rx and tx dboards) else{ //make the rx subdevs - BOOST_FOREACH(std::string subdev, rx_subdevs){ + BOOST_FOREACH(const std::string &subdev, rx_subdevs){ dboard_base::sptr rx_dboard = rx_dboard_ctor( - dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, ID_NONE) + dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, dboard_id::NONE) ); //create a rx proxy for this rx board _rx_dboards[subdev] = subdev_proxy::sptr( @@ -231,9 +232,9 @@ dboard_manager_impl::dboard_manager_impl( ); } //make the tx subdevs - BOOST_FOREACH(std::string subdev, tx_subdevs){ + BOOST_FOREACH(const std::string &subdev, tx_subdevs){ dboard_base::sptr tx_dboard = tx_dboard_ctor( - dboard_base::ctor_args_t(subdev, interface, ID_NONE, tx_dboard_id) + dboard_base::ctor_args_t(subdev, interface, dboard_id::NONE, tx_dboard_id) ); //create a tx proxy for this tx board _tx_dboards[subdev] = subdev_proxy::sptr( diff --git a/host/lib/usrp/usrp1e/usrp1e_none.cpp b/host/lib/usrp/usrp1e/usrp1e_none.cpp index ac0b12a75..94243523d 100644 --- a/host/lib/usrp/usrp1e/usrp1e_none.cpp +++ b/host/lib/usrp/usrp1e/usrp1e_none.cpp @@ -25,7 +25,7 @@ using namespace uhd::usrp; * when the required kernel module headers are not present. */ -device_addrs_t usrp1e::discover(const device_addr_t &){ +device_addrs_t usrp1e::find(const device_addr_t &){ return device_addrs_t(); //return empty list } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 66e02d469..fd72aeaa4 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -15,7 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/clock_config.hpp> #include <boost/format.hpp> #include "usrp2_impl.hpp" diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index d20465147..8fc7864b0 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> #include "usrp2_impl.hpp" using namespace uhd::usrp; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 34cce0afb..0d43fac0e 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> #include <boost/format.hpp> #include <boost/assign/list_of.hpp> #include <boost/math/special_functions/round.hpp> @@ -35,7 +35,7 @@ template <class T> T log2(T num){ /*********************************************************************** * DDC Helper Methods **********************************************************************/ -static boost::uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ +static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){ double scale_factor = std::pow(2.0, 32); //calculate the freq register word @@ -63,9 +63,8 @@ void usrp2_impl::init_ddc_config(void){ _ddc_freq = 0; update_ddc_config(); - _ddc_stream_at = time_spec_t(); - _ddc_enabled = false; - update_ddc_enabled(); + //initial command that kills streaming (in case if was left on) + //issue_ddc_stream_cmd(TODO) } void usrp2_impl::update_ddc_config(void){ @@ -86,21 +85,19 @@ void usrp2_impl::update_ddc_config(void){ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_TOTALLY_SETUP_THE_DDC_DUDE); } -void usrp2_impl::update_ddc_enabled(void){ +void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //setup the out data usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO); - out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; - out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); - out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); - out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); + out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO); + out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0; + out_data.data.stream_cmd.continuous = (stream_cmd.continuous)? 1 : 0; + out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); + out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks); + out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); - ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_CONFIGURED_THAT_STREAMING_DUDE); - - //clear the stream at time spec (it must be set for the next round of enable/disable) - _ddc_stream_at = time_spec_t(); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE); } /*********************************************************************** @@ -116,12 +113,12 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ case DSP_PROP_OTHERS:{ prop_names_t others = boost::assign::list_of - ("rate") + ("if_rate") + ("bb_rate") ("decim") ("decims") ("freq") - ("enabled") - ("stream_at") + ("stream_cmd") ; val = others; } @@ -131,10 +128,14 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ //handle string-based properties specific to this dsp std::string key_name = key.as<std::string>(); - if (key_name == "rate"){ + if (key_name == "if_rate"){ val = get_master_clock_freq(); return; } + else if (key_name == "bb_rate"){ + val = get_master_clock_freq()/_ddc_decim; + return; + } else if (key_name == "decim"){ val = _ddc_decim; return; @@ -147,10 +148,6 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_freq; return; } - else if (key_name == "enabled"){ - val = _ddc_enabled; - return; - } throw std::invalid_argument(str( boost::format("error getting: unknown key with name %s") % key_name @@ -171,23 +168,15 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "freq"){ - freq_t new_freq = val.as<freq_t>(); + double new_freq = val.as<double>(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _ddc_freq = new_freq; //shadow update_ddc_config(); return; } - else if (key_name == "enabled"){ - bool new_enabled = val.as<bool>(); - _ddc_enabled = new_enabled; //shadow - update_ddc_enabled(); - return; - } - else if (key_name == "stream_at"){ - time_spec_t new_stream_at = val.as<time_spec_t>(); - _ddc_stream_at = new_stream_at; //shadow - //update_ddc_enabled(); //dont update from here + else if (key_name == "stream_cmd"){ + issue_ddc_stream_cmd(val.as<stream_cmd_t>()); return; } @@ -250,7 +239,8 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ case DSP_PROP_OTHERS:{ prop_names_t others = boost::assign::list_of - ("rate") + ("if_rate") + ("bb_rate") ("interp") ("interps") ("freq") @@ -263,10 +253,14 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ //handle string-based properties specific to this dsp std::string key_name = key.as<std::string>(); - if (key_name == "rate"){ + if (key_name == "if_rate"){ val = get_master_clock_freq(); return; } + else if (key_name == "bb_rate"){ + val = get_master_clock_freq()/_duc_interp; + return; + } else if (key_name == "interp"){ val = _duc_interp; return; @@ -299,7 +293,7 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "freq"){ - freq_t new_freq = val.as<freq_t>(); + double new_freq = val.as<double>(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _duc_freq = new_freq; //shadow diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 7fcae6fb2..30fee6c32 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -32,6 +32,9 @@ extern "C" { #define _SINS_ #endif +//used to differentiate control packets over data port +#define USRP2_INVALID_VRT_HEADER 0 + // size of the vrt header and trailer to the host #define USRP2_HOST_RX_VRT_HEADER_WORDS32 5 #define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present @@ -90,8 +93,8 @@ typedef enum{ USRP2_CTRL_ID_SETUP_THIS_DDC_FOR_ME_BRO, USRP2_CTRL_ID_TOTALLY_SETUP_THE_DDC_DUDE, - USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO, - USRP2_CTRL_ID_CONFIGURED_THAT_STREAMING_DUDE, + USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO, + USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE, USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO, USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, @@ -186,12 +189,13 @@ typedef struct{ _SINS_ uint32_t scale_iq; } ddc_args; struct { - _SINS_ uint8_t enabled; - _SINS_ uint8_t _pad[3]; + _SINS_ uint8_t now; //stream now? + _SINS_ uint8_t continuous; //auto-reload commmands? + _SINS_ uint8_t _pad[2]; _SINS_ uint32_t secs; _SINS_ uint32_t ticks; - _SINS_ uint32_t samples; - } streaming; + _SINS_ uint32_t num_samps; + } stream_cmd; struct { _SINS_ uint32_t freq_word; _SINS_ uint32_t interp; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index dc8eea243..c87884ebb 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,7 +16,6 @@ // #include <complex> -#include <algorithm> #include <boost/format.hpp> #include "usrp2_impl.hpp" @@ -42,20 +41,22 @@ void usrp2_impl::io_init(void){ _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port - boost::uint32_t zero_data = 0; - _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); + //and the maximum number of lines (32 bit words) per packet + boost::uint32_t data[2] = { + htonl(USRP2_INVALID_VRT_HEADER), + htonl(_max_rx_samples_per_packet) + }; + _data_transport->send(asio::buffer(&data, sizeof(data))); } -#define unrolled_loop(__i, __len, __inst) {\ +#define unrolled_loop(__inst, __len){ \ size_t __i = 0; \ - while(__i < (__len & ~0x7)){ \ - __inst; __i++; __inst; __i++; \ - __inst; __i++; __inst; __i++; \ - __inst; __i++; __inst; __i++; \ - __inst; __i++; __inst; __i++; \ + for(; __i < (__len & ~0x3); __i+= 4){ \ + __inst(__i+0); __inst(__i+1); \ + __inst(__i+2); __inst(__i+3); \ } \ - while(__i < __len){ \ - __inst; __i++;\ + for(; __i < __len; __i++){ \ + __inst(__i); \ } \ } @@ -71,11 +72,12 @@ static inline void host_floats_to_usrp2_items( const fc32_t *host_floats, size_t num_samps ){ - unrolled_loop(i, num_samps,{ - boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); - boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); - usrp2_items[i] = htonl((real << 16) | (imag << 0)); - }); + #define host_floats_to_usrp2_items_i(i){ \ + boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ + boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ + usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ + } + unrolled_loop(host_floats_to_usrp2_items_i, num_samps); } static inline void usrp2_items_to_host_floats( @@ -83,12 +85,13 @@ static inline void usrp2_items_to_host_floats( const boost::uint32_t *usrp2_items, size_t num_samps ){ - unrolled_loop(i, num_samps,{ - boost::uint32_t item = ntohl(usrp2_items[i]); - boost::int16_t real = boost::uint16_t(item >> 16); - boost::int16_t imag = boost::uint16_t(item >> 0); - host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); - }); + #define usrp2_items_to_host_floats_i(i){ \ + boost::uint32_t item = ntohl(usrp2_items[i]); \ + boost::int16_t real = boost::uint16_t(item >> 16); \ + boost::int16_t imag = boost::uint16_t(item >> 0); \ + host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ + } + unrolled_loop(usrp2_items_to_host_floats_i, num_samps); } static inline void host_items_to_usrp2_items( @@ -96,11 +99,12 @@ static inline void host_items_to_usrp2_items( const boost::uint32_t *host_items, size_t num_samps ){ + #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) if (is_big_endian){ std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); } else{ - unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); + unrolled_loop(host_items_to_usrp2_items_i, num_samps); } } @@ -109,11 +113,12 @@ static inline void usrp2_items_to_host_items( const boost::uint32_t *usrp2_items, size_t num_samps ){ + #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) if (is_big_endian){ std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); } else{ - unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); + unrolled_loop(usrp2_items_to_host_items_i, num_samps); } } @@ -167,46 +172,43 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ size_t usrp2_impl::send( const asio::const_buffer &buff, const tx_metadata_t &metadata, - const std::string &type + const io_type_t &io_type ){ boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; - boost::uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data - size_t num_samps = _max_tx_samples_per_packet; - - //calculate the number of samples to be copied - //and copy the samples into the send buffer - if (type == "32fc"){ - num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); - host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); - } - else if (type == "16sc"){ - num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); - host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); - } - else{ - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); - } + size_t num_samps = std::min( + asio::buffer_size(buff)/io_type.size, + size_t(_max_tx_samples_per_packet) + ); - boost::uint32_t vrt_hdr[vrt::max_header_words32]; size_t num_header_words32, num_packet_words32; size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; //pack metadata into a vrt header vrt::pack( metadata, //input - vrt_hdr, //output + tx_mem, //output num_header_words32, //output num_samps, //input num_packet_words32, //output packet_count //input ); - //copy in the vrt header (yes we left space) - items -= num_header_words32; - std::memcpy(items, vrt_hdr, num_header_words32*sizeof(boost::uint32_t)); + boost::uint32_t *items = tx_mem + num_header_words32; //offset for data + + //copy the samples into the send buffer + switch(io_type.tid){ + case io_type_t::COMPLEX_FLOAT32: + host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); + break; + case io_type_t::COMPLEX_INT16: + host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); + break; + default: + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid)); + } //send and return number of samples - _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(boost::uint32_t))); + _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t))); return num_samps; } @@ -216,7 +218,7 @@ size_t usrp2_impl::send( size_t usrp2_impl::recv( const asio::mutable_buffer &buff, rx_metadata_t &metadata, - const std::string &type + const io_type_t &io_type ){ //perform a receive if no rx data is waiting to be copied if (asio::buffer_size(_rx_copy_buff) == 0){ @@ -232,21 +234,22 @@ size_t usrp2_impl::recv( //and a pointer into the usrp2 received items memory size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); if (bytes_to_copy == 0) return 0; //nothing to receive - size_t num_samps = bytes_to_copy/sizeof(boost::uint32_t); + size_t num_samps = std::min( + asio::buffer_size(buff)/io_type.size, + bytes_to_copy/sizeof(boost::uint32_t) + ); const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff); - //calculate the number of samples to be copied - //and copy the samples from the recv buffer - if (type == "32fc"){ - num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + //copy the samples from the recv buffer + switch(io_type.tid){ + case io_type_t::COMPLEX_FLOAT32: usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); - } - else if (type == "16sc"){ - num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + break; + case io_type_t::COMPLEX_INT16: usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); - } - else{ - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); + break; + default: + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid)); } //update the rx copy buffer to reflect the bytes copied diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index cbca8eec7..35dfd6287 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -15,7 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/mac_addr.hpp> #include "usrp2_impl.hpp" using namespace uhd; @@ -35,27 +36,10 @@ void usrp2_impl::mboard_init(void){ } void usrp2_impl::init_clock_config(void){ - //init the ref source clock config - _ref_source_dict = boost::assign::map_list_of - ("int", USRP2_REF_SOURCE_INT) - ("sma", USRP2_REF_SOURCE_SMA) - ("mimo", USRP2_REF_SOURCE_MIMO) - ; - _clock_config.ref_source = "int"; - - //init the pps source clock config - _pps_source_dict = boost::assign::map_list_of - ("sma", USRP2_PPS_SOURCE_SMA) - ("mimo", USRP2_PPS_SOURCE_MIMO) - ; - _clock_config.pps_source = "sma"; - - //init the pps polarity clock config - _pps_polarity_dict = boost::assign::map_list_of - (clock_config_t::POLARITY_POS, USRP2_PPS_POLARITY_POS) - (clock_config_t::POLARITY_NEG, USRP2_PPS_POLARITY_NEG) - ; - _clock_config.pps_polarity = clock_config_t::POLARITY_NEG; + //setup the clock configuration settings + _clock_config.ref_source = clock_config_t::REF_INT; + _clock_config.pps_source = clock_config_t::PPS_SMA; + _clock_config.pps_polarity = clock_config_t::PPS_NEG; //update the clock config (sends a control packet) update_clock_config(); @@ -65,9 +49,35 @@ void usrp2_impl::update_clock_config(void){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_HERES_A_NEW_CLOCK_CONFIG_BRO); - out_data.data.clock_config.ref_source = _ref_source_dict [_clock_config.ref_source]; - out_data.data.clock_config.pps_source = _pps_source_dict [_clock_config.pps_source]; - out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_clock_config.pps_polarity]; + + //translate ref source enums + switch(_clock_config.ref_source){ + case clock_config_t::REF_INT: + out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_INT; break; + case clock_config_t::REF_SMA: + out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_SMA; break; + case clock_config_t::REF_MIMO: + out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_MIMO; break; + default: throw std::runtime_error("usrp2: unhandled clock configuration ref source"); + } + + //translate pps source enums + switch(_clock_config.pps_source){ + case clock_config_t::PPS_SMA: + out_data.data.clock_config.pps_source = USRP2_PPS_SOURCE_SMA; break; + case clock_config_t::PPS_MIMO: + out_data.data.clock_config.pps_source = USRP2_PPS_SOURCE_MIMO; break; + default: throw std::runtime_error("usrp2: unhandled clock configuration pps source"); + } + + //translate pps polarity enums + switch(_clock_config.pps_polarity){ + case clock_config_t::PPS_POS: + out_data.data.clock_config.pps_source = USRP2_PPS_POLARITY_POS; break; + case clock_config_t::PPS_NEG: + out_data.data.clock_config.pps_source = USRP2_PPS_POLARITY_NEG; break; + default: throw std::runtime_error("usrp2: unhandled clock configuration pps polarity"); + } //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -106,7 +116,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); //extract the address - val = reinterpret_cast<mac_addr_t*>(in_data.data.mac_addr)->to_string(); + val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string(); return; } @@ -159,7 +169,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_CLOCK_RATE: - val = freq_t(get_master_clock_freq()); + val = double(get_master_clock_freq()); return; case MBOARD_PROP_RX_DSP: @@ -184,14 +194,6 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; - case MBOARD_PROP_PPS_SOURCE_NAMES: - val = prop_names_t(_pps_source_dict.get_keys()); - return; - - case MBOARD_PROP_REF_SOURCE_NAMES: - val = prop_names_t(_ref_source_dict.get_keys()); - return; - case MBOARD_PROP_TIME_NOW: case MBOARD_PROP_TIME_NEXT_PPS: throw std::runtime_error("Error: trying to get write-only property on usrp2 mboard"); @@ -209,8 +211,8 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO); - mac_addr_t mac_addr(val.as<std::string>()); - std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t)); + mac_addr_t mac_addr = mac_addr_t::from_string(val.as<std::string>()); + std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -234,13 +236,9 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the get request conditioned on the key switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_CLOCK_CONFIG:{ - clock_config_t clock_config = val.as<clock_config_t>(); - assert_has(_pps_source_dict.get_keys(), clock_config.pps_source, "usrp2 pps source"); - assert_has(_ref_source_dict.get_keys(), clock_config.ref_source, "usrp2 ref source"); - _clock_config = clock_config; //shadow - update_clock_config(); - } + case MBOARD_PROP_CLOCK_CONFIG: + _clock_config = val.as<clock_config_t>(); + update_clock_config(); return; case MBOARD_PROP_TIME_NOW:{ @@ -264,8 +262,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_RX_DBOARD_NAMES: case MBOARD_PROP_TX_DBOARD: case MBOARD_PROP_TX_DBOARD_NAMES: - case MBOARD_PROP_PPS_SOURCE_NAMES: - case MBOARD_PROP_REF_SOURCE_NAMES: throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard"); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 85d73e83a..67fbdf8d2 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -15,9 +15,12 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/transport/if_addrs.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> #include <boost/format.hpp> +#include <boost/foreach.hpp> #include <boost/bind.hpp> -#include <uhd/utils.hpp> #include <iostream> #include "usrp2_impl.hpp" @@ -27,16 +30,33 @@ using namespace uhd::transport; namespace asio = boost::asio; STATIC_BLOCK(register_usrp2_device){ - device::register_device(&usrp2::discover, &usrp2::make); + device::register_device(&usrp2::find, &usrp2::make); } /*********************************************************************** * Discovery over the udp transport **********************************************************************/ -uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ +uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ device_addrs_t usrp2_addrs; - if (not hint.has_key("addr")) return usrp2_addrs; + //if no address was specified, send a broadcast on each interface + if (not hint.has_key("addr")){ + BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){ + //avoid the loopback device + if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue; + + //create a new hint with this broadcast address + device_addr_t new_hint = hint; + new_hint["addr"] = if_addrs.bcast; + + //call discover with the new hint and append results + device_addrs_t new_usrp2_addrs = usrp2::find(new_hint); + usrp2_addrs.insert(usrp2_addrs.begin(), + new_usrp2_addrs.begin(), new_usrp2_addrs.end() + ); + } + return usrp2_addrs; + } //create a udp transport to communicate //TODO if an addr is not provided, search all interfaces? @@ -63,7 +83,6 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; new_addr["name"] = "USRP2"; - new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); //dont break here, it will exit the while loop diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 55ac0b192..3468a0cf1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -19,9 +19,10 @@ #define INCLUDED_USRP2_IMPL_HPP #include <uhd/usrp/usrp2.hpp> -#include <uhd/dict.hpp> -#include <uhd/types.hpp> -#include <uhd/time_spec.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/clock_config.hpp> +#include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> @@ -105,8 +106,8 @@ public: double get_master_clock_freq(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &); - size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); + size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); + size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &); private: //device properties interface @@ -146,11 +147,6 @@ private: void update_clock_config(void); void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - //mappings from clock config strings to over the wire enums - uhd::dict<std::string, usrp2_ref_source_t> _ref_source_dict; - uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict; - uhd::dict<uhd::clock_config_t::polarity_t, usrp2_pps_polarity_t> _pps_polarity_dict; - //rx and tx dboard methods and objects uhd::usrp::dboard_manager::sptr _dboard_manager; void dboard_init(void); @@ -177,16 +173,14 @@ private: //methods and shadows for the ddc dsp std::vector<size_t> _allowed_decim_and_interp_rates; size_t _ddc_decim; - uhd::freq_t _ddc_freq; - bool _ddc_enabled; - uhd::time_spec_t _ddc_stream_at; + double _ddc_freq; void init_ddc_config(void); void update_ddc_config(void); - void update_ddc_enabled(void); + void issue_ddc_stream_cmd(const uhd::stream_cmd_t &stream_cmd); //methods and shadows for the duc dsp size_t _duc_interp; - uhd::freq_t _duc_freq; + double _duc_freq; void init_duc_config(void); void update_duc_config(void); diff --git a/host/test/addr_test.cpp b/host/test/addr_test.cpp index 148aee015..a5d2d4c06 100644 --- a/host/test/addr_test.cpp +++ b/host/test/addr_test.cpp @@ -16,13 +16,52 @@ // #include <boost/test/unit_test.hpp> -#include <uhd/device_addr.hpp> +#include <uhd/types/mac_addr.hpp> +#include <uhd/types/device_addr.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/foreach.hpp> +#include <algorithm> +#include <iostream> BOOST_AUTO_TEST_CASE(test_mac_addr){ std::cout << "Testing mac addr..." << std::endl; const std::string mac_addr_str("00:01:23:45:67:89"); - uhd::mac_addr_t mac_addr(mac_addr_str); + uhd::mac_addr_t mac_addr = uhd::mac_addr_t::from_string(mac_addr_str); std::cout << "Input: " << mac_addr_str << std::endl; - std::cout << "Output: " << mac_addr << std::endl; + std::cout << "Output: " << mac_addr.to_string() << std::endl; BOOST_CHECK_EQUAL(mac_addr_str, mac_addr.to_string()); } + +BOOST_AUTO_TEST_CASE(test_device_addr){ + std::cout << "Testing device addr..." << std::endl; + + //load the device address with something + uhd::device_addr_t dev_addr; + dev_addr["key1"] = "val1"; + dev_addr["key2"] = "val2"; + + //convert to and from args string + std::cout << "Pretty Print: " << std::endl << dev_addr.to_string(); + std::string args_str = dev_addr.to_args_str(); + std::cout << "Args String: " << args_str << std::endl; + uhd::device_addr_t new_dev_addr = uhd::device_addr_t::from_args_str(args_str); + + //they should be the same size + BOOST_CHECK_EQUAL(dev_addr.size(), new_dev_addr.size()); + + //the keys should match + std::vector<std::string> old_dev_addr_keys = dev_addr.get_keys(); + std::vector<std::string> new_dev_addr_keys = new_dev_addr.get_keys(); + BOOST_CHECK_EQUAL_COLLECTIONS( + old_dev_addr_keys.begin(), old_dev_addr_keys.end(), + new_dev_addr_keys.begin(), new_dev_addr_keys.end() + ); + + //the vals should match + std::vector<std::string> old_dev_addr_vals = dev_addr.get_vals(); + std::vector<std::string> new_dev_addr_vals = new_dev_addr.get_vals(); + BOOST_CHECK_EQUAL_COLLECTIONS( + old_dev_addr_vals.begin(), old_dev_addr_vals.end(), + new_dev_addr_vals.begin(), new_dev_addr_vals.end() + ); +} diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index 47acb30f0..76b065ce2 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -16,10 +16,10 @@ // #include <boost/test/unit_test.hpp> -#include <uhd/gain_handler.hpp> -#include <uhd/types.hpp> +#include <uhd/utils/gain_handler.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/dict.hpp> #include <uhd/props.hpp> -#include <uhd/dict.hpp> #include <boost/bind.hpp> #include <iostream> @@ -46,8 +46,8 @@ public: ); _gain_values["g0"] = 0; _gain_values["g1"] = 0; - _gain_ranges["g0"] = gain_range_t(-10, 0, .1); - _gain_ranges["g1"] = gain_range_t(0, 100, 1.5); + _gain_ranges["g0"] = gain_range_t(-10, 0, float(.1)); + _gain_ranges["g1"] = gain_range_t(0, 100, float(1.5)); } ~gainful_obj(void){} @@ -84,7 +84,7 @@ private: //handle the get request conditioned on the key switch(key.as<prop_t>()){ case PROP_GAIN_VALUE: - _gain_values[name] = val.as<gain_t>(); + _gain_values[name] = val.as<float>(); return; case PROP_GAIN_RANGE: @@ -94,7 +94,7 @@ private: } gain_handler::sptr _gain_handler; - uhd::dict<std::string, gain_t> _gain_values; + uhd::dict<std::string, float> _gain_values; uhd::dict<std::string, gain_range_t> _gain_ranges; }; @@ -104,18 +104,18 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ gainful_obj go0; BOOST_CHECK_THROW( - go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<gain_t>(), + go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<float>(), std::exception ); std::cout << "verifying the overall min, max, step" << std::endl; gain_range_t gain = go0[PROP_GAIN_RANGE].as<gain_range_t>(); - BOOST_CHECK_EQUAL(gain.min, gain_t(-10)); - BOOST_CHECK_EQUAL(gain.max, gain_t(100)); - BOOST_CHECK_EQUAL(gain.step, gain_t(1.5)); + BOOST_CHECK_EQUAL(gain.min, float(-10)); + BOOST_CHECK_EQUAL(gain.max, float(100)); + BOOST_CHECK_EQUAL(gain.step, float(1.5)); std::cout << "verifying the overall gain" << std::endl; - go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = gain_t(-5); - go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = gain_t(30); - BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<gain_t>(), gain_t(25)); + go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = float(-5); + go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = float(30); + BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<float>(), float(25)); } diff --git a/host/test/module_test.cpp b/host/test/module_test.cpp index 71721ef90..47a0e1af9 100644 --- a/host/test/module_test.cpp +++ b/host/test/module_test.cpp @@ -15,10 +15,10 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/utils.hpp> +#include <uhd/utils/static.hpp> #include <iostream> -STATIC_BLOCK(module_test){ +UHD_STATIC_BLOCK(module_test){ std::cout << "---------------------------------------" << std::endl; std::cout << "-- Good news, everyone!" << std::endl; std::cout << "-- The test module has been loaded." << std::endl; diff --git a/host/test/wax_test.cpp b/host/test/wax_test.cpp index cb3b12052..731f470ed 100644 --- a/host/test/wax_test.cpp +++ b/host/test/wax_test.cpp @@ -16,6 +16,7 @@ // #include <boost/test/unit_test.hpp> +#include <boost/shared_ptr.hpp> #include <uhd/wax.hpp> #include <iostream> @@ -32,26 +33,29 @@ BOOST_AUTO_TEST_CASE(test_enums){ * demo class for wax framework **********************************************************************/ class wax_demo : public wax::obj{ -private: - std::vector<float> d_nums; - std::vector<wax_demo> d_subs; public: + typedef boost::shared_ptr<wax_demo> sptr; + wax_demo(size_t sub_demos, size_t len){ d_nums = std::vector<float>(len); if (sub_demos != 0){ for (size_t i = 0; i < len; i++){ - d_subs.push_back(wax_demo(sub_demos-1, len)); + d_subs.push_back(sptr(new wax_demo(sub_demos-1, len))); } } } ~wax_demo(void){ /* NOP */ } +private: + std::vector<float> d_nums; + std::vector<sptr> d_subs; + void get(const wax::obj &key, wax::obj &value){ if (d_subs.size() == 0){ value = d_nums[key.as<size_t>()]; }else{ - value = d_subs[key.as<size_t>()].get_link(); + value = d_subs[key.as<size_t>()]->get_link(); } } void set(const wax::obj &key, const wax::obj &value){ @@ -63,9 +67,8 @@ public: } }; -static wax_demo wd(2, 10); - BOOST_AUTO_TEST_CASE(test_chaining){ + wax_demo wd(2, 1); std::cout << "chain 1" << std::endl; wd[size_t(0)]; std::cout << "chain 2" << std::endl; @@ -75,6 +78,7 @@ BOOST_AUTO_TEST_CASE(test_chaining){ } BOOST_AUTO_TEST_CASE(test_set_get){ + wax_demo wd(2, 10); std::cout << "set and get all" << std::endl; for (size_t i = 0; i < 10; i++){ for (size_t j = 0; j < 10; j++){ @@ -89,6 +93,7 @@ BOOST_AUTO_TEST_CASE(test_set_get){ } BOOST_AUTO_TEST_CASE(test_proxy){ + wax_demo wd(2, 1); std::cout << "store proxy" << std::endl; wax::obj p = wd[size_t(0)][size_t(0)]; p[size_t(0)] = float(5); diff --git a/host/uhd.pc.in b/host/uhd.pc.in index 59ba623f5..2a34e9cfd 100644 --- a/host/uhd.pc.in +++ b/host/uhd.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIBRARY_DIR@ -includedir=${prefix}/@HEADER_DIR@ +includedir=${prefix}/@INCLUDE_DIR@ Name: @CPACK_PACKAGE_NAME@ Description: Universal Hardware Driver diff --git a/host/apps/CMakeLists.txt b/host/utils/CMakeLists.txt index 58f73fcd6..99e648d8a 100644 --- a/host/apps/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -15,12 +15,15 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -ADD_EXECUTABLE(discover_usrps discover_usrps.cpp) -TARGET_LINK_LIBRARIES(discover_usrps uhd) -INSTALL(TARGETS discover_usrps RUNTIME DESTINATION ${RUNTIME_DIR}) +ADD_EXECUTABLE(uhd_find_devices uhd_find_devices.cpp) +TARGET_LINK_LIBRARIES(uhd_find_devices uhd) +INSTALL(TARGETS uhd_find_devices RUNTIME DESTINATION ${RUNTIME_DIR}) ADD_EXECUTABLE(usrp1e_load_fpga usrp1e_load_fpga.cpp) TARGET_LINK_LIBRARIES(usrp1e_load_fpga uhd) ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp) TARGET_LINK_LIBRARIES(usrp2_burner uhd) +INSTALL(TARGETS usrp2_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) + +INSTALL(PROGRAMS usrp2_recovery.py DESTINATION ${PKG_DATA_DIR}/utils) diff --git a/host/apps/discover_usrps.cpp b/host/utils/uhd_find_devices.cpp index d670d1651..b328216d0 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/utils/uhd_find_devices.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/utils/safe_main.hpp> #include <uhd/device.hpp> #include <uhd/props.hpp> #include <boost/program_options.hpp> @@ -23,7 +24,7 @@ namespace po = boost::program_options; -int main(int argc, char *argv[]){ +int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") @@ -33,11 +34,11 @@ int main(int argc, char *argv[]){ po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + po::notify(vm); //print the help message if (vm.count("help")){ - std::cout << boost::format("Discover USRPs %s") % desc << std::endl; + std::cout << boost::format("UHD Find Devices %s") % desc << std::endl; return ~0; } @@ -51,18 +52,18 @@ int main(int argc, char *argv[]){ } //discover the usrps and print the results - uhd::device_addrs_t device_addrs = uhd::device::discover(device_addr); + uhd::device_addrs_t device_addrs = uhd::device::find(device_addr); if (device_addrs.size() == 0){ - std::cerr << "No USRP Devices Found" << std::endl; + std::cerr << "No UHD Devices Found" << std::endl; return ~0; } for (size_t i = 0; i < device_addrs.size(); i++){ std::cout << "--------------------------------------------------" << std::endl; - std::cout << "-- USRP Device " << i << std::endl; + std::cout << "-- UHD Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; - std::cout << device_addrs[i] << std::endl << std::endl; + std::cout << device_addrs[i].to_string() << std::endl << std::endl; uhd::device::make(device_addrs[i]); //test make } diff --git a/host/apps/usrp2_burner.cpp b/host/utils/usrp2_burner.cpp index 941e71d0c..b24425316 100644 --- a/host/apps/usrp2_burner.cpp +++ b/host/utils/usrp2_burner.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/utils/safe_main.hpp> #include <uhd/usrp/usrp2.hpp> #include <uhd/props.hpp> #include <boost/program_options.hpp> @@ -23,7 +24,7 @@ namespace po = boost::program_options; -int main(int argc, char *argv[]){ +int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") @@ -56,27 +57,32 @@ int main(int argc, char *argv[]){ uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr); //FIXME usees the default mboard for now (until the mimo link is supported) wax::obj u2_mb = (*u2_dev)[uhd::DEVICE_PROP_MBOARD]; + std::cout << std::endl; + + //fetch and print current settings + std::cout << "Fetching current settings from usrp2 eeprom:" << std::endl; + std::string curr_ip = u2_mb[std::string("ip-addr")].as<std::string>(); + std::cout << boost::format(" Current IP Address: %s") % curr_ip << std::endl; + std::string curr_mac = u2_mb[std::string("mac-addr")].as<std::string>(); + std::cout << boost::format(" Current MAC Address: %s") % curr_mac << std::endl; + std::cout << " Done" << std::endl << std::endl; //try to set the new ip (if provided) if (vm.count("new-ip")){ std::cout << "Burning a new ip address into the usrp2 eeprom:" << std::endl; - std::string old_ip = u2_mb[std::string("ip-addr")].as<std::string>(); - std::cout << boost::format(" Old IP Address: %s") % old_ip << std::endl; std::string new_ip = vm["new-ip"].as<std::string>(); std::cout << boost::format(" New IP Address: %s") % new_ip << std::endl; u2_mb[std::string("ip-addr")] = new_ip; - std::cout << " Done" << std::endl; + std::cout << " Done" << std::endl << std::endl; } //try to set the new mac (if provided) if (vm.count("new-mac")){ std::cout << "Burning a new mac address into the usrp2 eeprom:" << std::endl; - std::string old_mac = u2_mb[std::string("mac-addr")].as<std::string>(); - std::cout << boost::format(" Old MAC Address: %s") % old_mac << std::endl; std::string new_mac = vm["new-mac"].as<std::string>(); std::cout << boost::format(" New MAC Address: %s") % new_mac << std::endl; u2_mb[std::string("mac-addr")] = new_mac; - std::cout << " Done" << std::endl; + std::cout << " Done" << std::endl << std::endl; } std::cout << "Power-cycle the usrp2 for the changes to take effect." << std::endl; diff --git a/host/apps/usrp2_recovery.py b/host/utils/usrp2_recovery.py index 48c1121cb..5654e93d3 100755 --- a/host/apps/usrp2_recovery.py +++ b/host/utils/usrp2_recovery.py @@ -1,4 +1,20 @@ #!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# """ The usrp2 recovery app: |