diff options
78 files changed, 2811 insertions, 1069 deletions
diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/Makefile.am index ff426cf8c..a4f79935b 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/Makefile.am @@ -23,7 +23,7 @@ LDADD = $(top_srcdir)/lib/libu2fw.a  AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp -noinst_PROGRAMS = txrx.elf +noinst_PROGRAMS = txrx_uhd.elf  #	blink_leds \  #	blink_leds2 \ @@ -66,7 +66,7 @@ noinst_PROGRAMS = txrx.elf  # tx_drop_SOURCES = tx_drop.c app_common.c  # tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c  # tx_drop2_SOURCES = tx_drop2.c app_common.c -txrx_elf_SOURCES = txrx.c +txrx_uhd_elf_SOURCES = txrx_uhd.c  # app_common_v2.c  #factory_test_SOURCES = factory_test.c app_common_v2.c  #eth_serdes_SOURCES = eth_serdes.c app_passthru_v2.c diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx_uhd.c index 561f3148f..8ff3b8c58 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -45,13 +45,12 @@  #include "clocks.h"  #include <vrt/bits.h>  #include "usrp2/fw_common.h" -#include <db.h>  #include <i2c.h> -#include <lsdac.h> -#include <lsadc.h>  #include <ethertype.h>  #include <arp_cache.h> +#define LEDS_SW LED_A +  /*   * Full duplex Tx and Rx between ethernet and DSP pipelines   * @@ -203,20 +202,34 @@ void handle_udp_ctrl_packet(      unsigned char *payload, int payload_len  ){      //printf("Got ctrl packet #words: %d\n", (int)payload_len); +    usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; +    uint32_t ctrl_data_in_id = ctrl_data_in->id; + +    //ensure that the protocol versions match +    if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ +        printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", +            USRP2_PROTO_VERSION, ctrl_data_in->proto_ver +        ); +        ctrl_data_in_id = USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO; +    } + +    //ensure that this is not a short packet      if (payload_len < sizeof(usrp2_ctrl_data_t)){ -        //TODO send err packet -        return; +        printf("!Error in control packet handler: Expected payload length %d, but got %d\n", +            (int)sizeof(usrp2_ctrl_data_t), payload_len +        ); +        ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT;      } -    //setup the input and output data -    usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; +    //setup the output data      usrp2_ctrl_data_t ctrl_data_out = { +        .proto_ver = USRP2_PROTO_VERSION,          .id=USRP2_CTRL_ID_HUH_WHAT,          .seq=ctrl_data_in->seq      };      //handle the data based on the id -    switch(ctrl_data_in->id){ +    switch(ctrl_data_in_id){      /*******************************************************************       * Addressing @@ -243,12 +256,6 @@ void handle_udp_ctrl_packet(          memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t));          break; -    case USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO: -        ctrl_data_out.id = USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE; -        ctrl_data_out.data.dboard_ids.tx_id = read_dboard_eeprom(I2C_ADDR_TX_A); -        ctrl_data_out.data.dboard_ids.rx_id = read_dboard_eeprom(I2C_ADDR_RX_A); -        break; -      /*******************************************************************       * SPI       ******************************************************************/ @@ -297,43 +304,6 @@ void handle_udp_ctrl_packet(          break;      /******************************************************************* -     * AUX DAC/ADC -     ******************************************************************/ -    case USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO: -        if (ctrl_data_in->data.aux_args.dir == USRP2_DIR_RX){ -            lsdac_write_rx( -                ctrl_data_in->data.aux_args.which, -                ctrl_data_in->data.aux_args.value -            ); -        } - -        if (ctrl_data_in->data.aux_args.dir == USRP2_DIR_TX){ -            lsdac_write_tx( -                ctrl_data_in->data.aux_args.which, -                ctrl_data_in->data.aux_args.value -            ); -        } - -        ctrl_data_out.id = USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE; -        break; - -    case USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO: -        if (ctrl_data_in->data.aux_args.dir == USRP2_DIR_RX){ -            ctrl_data_out.data.aux_args.value = lsadc_read_rx( -                ctrl_data_in->data.aux_args.which -            ); -        } - -        if (ctrl_data_in->data.aux_args.dir == USRP2_DIR_TX){ -            ctrl_data_out.data.aux_args.value = lsadc_read_tx( -                ctrl_data_in->data.aux_args.which -            ); -        } - -        ctrl_data_out.id = USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE; -        break; - -    /*******************************************************************       * Streaming       ******************************************************************/      case USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO:{ @@ -342,6 +312,7 @@ void handle_udp_ctrl_packet(          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); +            hal_set_leds(LED_A, LEDS_SW);              auto_reload_command = true;              streaming_frame_count = FRAMES_PER_CMD; @@ -366,6 +337,7 @@ void handle_udp_ctrl_packet(          //issue regular stream commands (split commands if too large)          else{ +            hal_set_leds(0, LEDS_SW);              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 @@ -611,6 +583,7 @@ main(void)    print_mac_addr(ethernet_mac_addr()->addr);    newline();    print_ip_addr(get_ip_addr()); newline(); +  printf("Control protocol version: %d\n", USRP2_PROTO_VERSION);    ethernet_register_link_changed_callback(link_changed_callback);    ethernet_init(); @@ -621,6 +594,8 @@ main(void)    register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);    register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); +  hal_set_led_src(0, LEDS_SW); +  #if 0    // make bit 15 of Tx gpio's be a s/w output    hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am index 3d02cfe8b..783895850 100644 --- a/firmware/microblaze/lib/Makefile.am +++ b/firmware/microblaze/lib/Makefile.am @@ -28,7 +28,6 @@ libu2fw_a_SOURCES = \  	bsm12.c \  	buffer_pool.c \  	clocks.c \ -	db_init.c \  	dbsm.c \  	eeprom.c \  	ethernet.c \ @@ -38,8 +37,6 @@ libu2fw_a_SOURCES = \  	hal_io.c \  	hal_uart.c \  	i2c.c \ -	lsadc.c \ -	lsdac.c \  	mdelay.c \  	memcpy_wa.c \  	memset_wa.c \ @@ -62,7 +59,6 @@ noinst_HEADERS = \  	bsm12.h \  	buffer_pool.h \  	clocks.h \ -	db.h \  	dbsm.h \  	eth_mac.h \  	eth_mac_regs.h \ @@ -71,8 +67,6 @@ noinst_HEADERS = \  	hal_io.h \  	hal_uart.h \  	i2c.h \ -	lsadc.h \ -	lsdac.h \  	mdelay.h \  	memcpy_wa.h \  	memory_map.h \ diff --git a/firmware/microblaze/lib/db.h b/firmware/microblaze/lib/db.h deleted file mode 100644 index 358cb222b..000000000 --- a/firmware/microblaze/lib/db.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2009 Free Software Foundation, Inc. - * - * 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/>. - */ - -/* - * Interface to daughterboard code - */ - -#ifndef INCLUDED_DB_H -#define INCLUDED_DB_H - -#include <usrp2_types.h> -#include <usrp2_i2c_addr.h> - -int read_dboard_eeprom(int i2c_addr); - -#endif /* INCLUDED_DB_H */ diff --git a/firmware/microblaze/lib/db_init.c b/firmware/microblaze/lib/db_init.c deleted file mode 100644 index 23805d9cd..000000000 --- a/firmware/microblaze/lib/db_init.c +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -/* - * Copyright 2008,2009 Free Software Foundation, Inc. - * - * 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 <memory_map.h> -#include <i2c.h> -#include <string.h> -#include <stdio.h> -#include <db.h> -#include <hal_io.h> -#include <nonstdio.h> - - -typedef enum { UDBE_OK, UDBE_NO_EEPROM, UDBE_INVALID_EEPROM } usrp_dbeeprom_status_t; - -static usrp_dbeeprom_status_t -read_raw_dboard_eeprom (unsigned char *buf, int i2c_addr) -{ -  if (!eeprom_read (i2c_addr, 0, buf, DB_EEPROM_CLEN)) -    return UDBE_NO_EEPROM; - -  if (buf[DB_EEPROM_MAGIC] != DB_EEPROM_MAGIC_VALUE) -    return UDBE_INVALID_EEPROM; - -  int sum = 0; -  unsigned int i; -  for (i = 0; i < DB_EEPROM_CLEN; i++) -    sum += buf[i]; - -  if ((sum & 0xff) != 0) -    return UDBE_INVALID_EEPROM; - -  return UDBE_OK; -} - - -/* - * Return DBID, -1 <none> or -2 <invalid eeprom contents> - */ -int -read_dboard_eeprom(int i2c_addr) -{ -  unsigned char buf[DB_EEPROM_CLEN]; - -  usrp_dbeeprom_status_t s = read_raw_dboard_eeprom (buf, i2c_addr); - -  //printf("\nread_raw_dboard_eeprom: %d\n", s); - -  switch (s){ -  case UDBE_OK: -    return (buf[DB_EEPROM_ID_MSB] << 8) | buf[DB_EEPROM_ID_LSB]; - -  case UDBE_NO_EEPROM: -  default: -    return -1; - -  case UDBE_INVALID_EEPROM: -    return -2; -  } -} diff --git a/firmware/microblaze/lib/lsadc.c b/firmware/microblaze/lib/lsadc.c deleted file mode 100644 index 7983552e7..000000000 --- a/firmware/microblaze/lib/lsadc.c +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * 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 "lsadc.h" -#include "spi.h" -#include "memory_map.h" - - -// AD9712 or AD7922   1 MS/s, 10-/12-bit ADCs - -//#define SPI_SS_DEBUG SPI_SS_RX_DB -#define SPI_SS_DEBUG 0 - - -void  -lsadc_init(void) -{ -  // nop -} - -/*  - * The ADC's are pipelined.   That is, you have to tell them - * which of the two inputs you want one cycle ahead of time. - * We could optimize and keep track of which one we used last - * time, but for simplicity we'll always tell it which - * one we want.  This takes 2 16-bit xfers, one to set the - * input and one to read the one we want. - */ - -int -_lsadc_read(int which_adc, int slave_select) -{ -  uint32_t r; -  int channel = which_adc & 0x1; - -  // Set CHN and STY equal to channel number.  We don't want "daisy chain mode" -  uint16_t cmd = (channel << 13) | (channel << 12); - -  spi_transact(SPI_TXONLY, slave_select | SPI_SS_DEBUG, -	       cmd, 16, SPIF_PUSH_RISE | SPIF_LATCH_RISE); - -  r = spi_transact(SPI_TXRX, slave_select | SPI_SS_DEBUG, -		   cmd, 16, SPIF_PUSH_RISE | SPIF_LATCH_RISE); - -  return r & 0x0fff; -} - -int -lsadc_read_rx(int which_adc) -{ -  return _lsadc_read(which_adc, SPI_SS_RX_ADC); -} - -int -lsadc_read_tx(int which_adc) -{ -  return _lsadc_read(which_adc, SPI_SS_TX_ADC); -} diff --git a/firmware/microblaze/lib/lsadc.h b/firmware/microblaze/lib/lsadc.h deleted file mode 100644 index 319f34d91..000000000 --- a/firmware/microblaze/lib/lsadc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * 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_LSADC_H -#define INCLUDED_LSADC_H - -#include "memory_map.h" - -/*! - * \brief One time call to initialize low-speed ADCs. - */ -void lsadc_init(void); - -/*! - * \brief Read one of the low-speed Rx daughterboard ADCs. - * \param which_adc in [0, 1] - * - * \returns 12-bit value in [0,4095] - */ -int lsadc_read_rx(int which_adc); - -/*! - * \brief Read one of the low-speed Tx daughterboard ADCs. - * \param which_adc in [0, 1] - * - * \returns 12-bit value in [0,4095] - */ -int lsadc_read_tx(int which_adc); - - -#endif /* INCLUDED_LSADC_H */ diff --git a/firmware/microblaze/lib/lsdac.c b/firmware/microblaze/lib/lsdac.c deleted file mode 100644 index 6bc2e5cb5..000000000 --- a/firmware/microblaze/lib/lsdac.c +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * 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 "lsdac.h" -#include "spi.h" -#include "memory_map.h" - -// AD5624, AD5623 - -#define CMD(x)		  ((x) << 19) -#define CMD_WR_INPUT_N	     CMD(0)   // write input N -#define	CMD_UP_DAC_N	     CMD(1)   // update DAC N from input reg -#define CMD_WR_INPUT_N_LDAC  CMD(2)   // write input N, update all -#define	CMD_WR_UP_DAC_N	     CMD(3)   // write and update N -#define CMD_WR_PWR_CONFIG    CMD(4)   // write power up/down config reg -#define	CMD_SW_RESET	     CMD(5)   // force s/w reset -#define	CMD_WR_LDAC_CFG	     CMD(6)   // write LDAC config reg -#define	CMD_WR_INT_REF_CFG   CMD(7)   // write internal ref cfg reg (AD5623R only) - - -//#define SPI_SS_DEBUG SPI_SS_TX_DB -#define SPI_SS_DEBUG 0 - -inline static void -_write_rx(uint32_t v) -{ -  spi_transact(SPI_TXONLY, SPI_SS_RX_DAC | SPI_SS_DEBUG, v, 24, SPIF_PUSH_RISE); -} - -inline static void -_write_tx(uint32_t v) -{ -  spi_transact(SPI_TXONLY, SPI_SS_TX_DAC | SPI_SS_DEBUG, v, 24, SPIF_PUSH_RISE); -} - -void  -lsdac_init(void) -{ -  _write_tx(CMD_SW_RESET | 0x1);		// power-on reset -  _write_rx(CMD_SW_RESET | 0x1);		// power-on reset -} - -void -lsdac_write_rx(int which_dac, int value) -{ -  _write_rx(CMD_WR_UP_DAC_N | ((which_dac & 0x7) << 16) | ((value << 4) & 0xffff)); -} - -void -lsdac_write_tx(int which_dac, int value) -{ -  _write_tx(CMD_WR_UP_DAC_N | ((which_dac & 0x7) << 16) | ((value << 4) & 0xffff)); -} diff --git a/firmware/microblaze/lib/lsdac.h b/firmware/microblaze/lib/lsdac.h deleted file mode 100644 index 9cad917e3..000000000 --- a/firmware/microblaze/lib/lsdac.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * 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_LSDAC_H -#define INCLUDED_LSDAC_H - -#include "memory_map.h" - -/*! - * \brief One time call to initialize low-speed DACs. - */ -void lsdac_init(void); - -/*! - * \brief Write one of the low-speed Rx daughterboard DACs. - * \param which_dac in [0, 3] - * \param unsigned 12-bit value in [0, 4095] - * - * value maps linearly to output voltage from 0 to 3.3V - */ -void lsdac_write_rx(int which_dac, int value); - -/*! - * \brief Write one of the low-speed Tx daughterboard DACs. - * \param which_dac in [0, 3] - * \param unsigned 12-bit value in [0, 4095] - * - * value maps linearly to output voltage from 0 to 3.3V - */ -void lsdac_write_tx(int which_dac, int value); - - -#endif /* INCLUDED_LSDAC_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index bd3302d95..399d834cb 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -20,14 +20,11 @@  #include "spi.h"  #include "pic.h"  #include "hal_io.h" -#include "lsadc.h" -#include "lsdac.h"  #include "buffer_pool.h"  #include "hal_uart.h"  #include "i2c.h"  #include "mdelay.h"  #include "clocks.h" -#include "db.h"  #include "usrp2_i2c_addr.h"  //#include "nonstdio.h" @@ -84,8 +81,6 @@ u2_init(void)    pic_init();	// progammable interrupt controller    bp_init();	// buffer pool -  lsadc_init();	    // low-speed ADCs -  lsdac_init();	    // low-speed DACs    hal_enable_ints(); diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 6334b44ff..bf8d71b21 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -76,7 +76,7 @@ ENDIF(WIN32)  # Setup Boost  ########################################################################  SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42") -FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS +FIND_PACKAGE(Boost 1.37 REQUIRED COMPONENTS      date_time      filesystem      program_options @@ -124,24 +124,8 @@ INSTALL(  )  ######################################################################## -# Setup Docs +# Install Package Docs  ######################################################################## -INCLUDE(FindDoxygen) - -IF(DOXYGEN_FOUND) -    SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen) -    CONFIGURE_FILE( -        ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in -        ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile -    @ONLY) -    ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} -        COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile -        COMMENT "Generating documentation with doxygen" -    ) -    ADD_CUSTOM_TARGET(docs ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN}) -    INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DESTINATION ${PKG_DOC_DIR}) -ENDIF(DOXYGEN_FOUND) -  INSTALL(FILES      ${CMAKE_CURRENT_SOURCE_DIR}/README      ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE @@ -152,6 +136,7 @@ INSTALL(FILES  ########################################################################  # Add the subdirectories  ######################################################################## +ADD_SUBDIRECTORY(docs)  ADD_SUBDIRECTORY(examples)  ADD_SUBDIRECTORY(include)  ADD_SUBDIRECTORY(lib) diff --git a/host/README b/host/README index cbf18dbf7..e67bb25f8 100644 --- a/host/README +++ b/host/README @@ -15,86 +15,15 @@ Basic RX  Basic TX  LF RX  LF TX +RFX Series +XCVR 2450  ######################################################################## -# Dependencies +# Documentation  ######################################################################## -Unix Notes: -    These dependencies can be acquired through the package manager. -Windows Notes: -    These dependencies can be acquired through installable exe files. -    Usually, the windows installer can be found on the project's website. -    Some projects do not host windows installers, and if this is the case, -    follow the auxiliary download url for the windows installer (below). - -Git: -    Required to check out the repository (not needed for source downloads). -    On windows, install cygwin with git support to checkout the repository. - -C++: -    On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008. -    Other compilers have not been tested yet or confirmed working. - -CMake: -    Version: at least 2.8 -    Required for: build time -    Download URL: http://www.cmake.org/cmake/resources/software.html - -Boost: -    Version: at least 3.6 unix, at least 4.0 windows -    Required for: build time + run time -    Download URL: http://www.boost.org/users/download/ -    Download URL (windows installer): http://www.boostpro.com/download - -Python: -    Version: at least 2.6 -    Required for: build time -    Download URL: http://www.python.org/download/ - -Cheetah: -    Version: at least 2.0 -    Required for: build time -    Download URL: http://www.cheetahtemplate.org/download.html -    Download URL (windows installer): http://feisley.com/python/cheetah/ - -Doxygen: -    Required for: build time (optional) -    Download URL: http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc - -######################################################################## -# Build Instructions (unix) -######################################################################## -cd <uhd-repo-path>/host -mkdir build -cd build -cmake ../ -make -make test -sudo make install - -For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../ - -######################################################################## -# Build Instructions (windows) -######################################################################## - -##### Generate the project with cmake ##### -Open the cmake gui program. -Set the path to the source code: <uhd-repo-path>/host -Set the path to the build directory: <uhd-repo-path>/host/build -Make sure that the paths do not contain spaces. -Click configure and select the MSVC compiler. -Set the build variables and click configure again. -Click generate and a project file will be created in the build directory. - -##### Build the project in MSVC ##### -Open the generated project file in MSVC. -Select the build all target, right click, and choose build. -Select the install target, right click, and choose build. -    Note: you may not have permission to build the install target. -    You need to be an administrator or to run MSVC as administrator. - -##### Setup the PATH environment variable ##### -Add the boost library path and uhd library path to your %PATH%. -Usually c:\program files\boost\<version>\lib and c:\program files\uhd\lib +Online documentation available at: +http://ettus-apps.sourcerepo.com/redmine/ettus/projects/uhd/wiki/ +The build system can generate the html for the manual and Doxygen. +Docutils and Doxygen are required to build the html docs. +See the docs directory for the manual source (reStructuredText). diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt new file mode 100644 index 000000000..61eede8b7 --- /dev/null +++ b/host/docs/CMakeLists.txt @@ -0,0 +1,101 @@ +# +# 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/>. +# + +######################################################################## +# List of manual sources +######################################################################## +SET(manual_sources +    index.rst +    build.rst +    coding.rst +    dboards.rst +    usrp2.rst +) + +######################################################################## +# Setup Manual +######################################################################## +MESSAGE(STATUS "Checking for rst2html (docutils)") +FIND_PROGRAM(RST2HTML rst2html) +IF(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") +    MESSAGE(STATUS "Checking for rst2html (docutils) - not found") +    MESSAGE(STATUS "  Disabled generation of HTML manual.") +ELSE(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") +    MESSAGE(STATUS "Checking for rst2html (docutils) - found") +    MESSAGE(STATUS "  Enabled generation of HTML manual.") + +    #setup rst2html options +    SET(stylesheet ${CMAKE_CURRENT_SOURCE_DIR}/style.css) +    SET(rst2html_options +        --stylesheet=${stylesheet} +        --no-toc-backlinks --date --time +    ) + +    #create generation rule for each source +    FOREACH(rstfile ${manual_sources}) +        #set input and output file names +        SET(rstfile ${CMAKE_CURRENT_SOURCE_DIR}/${rstfile}) +        GET_FILENAME_COMPONENT(rstfile_we ${rstfile} NAME_WE) +        SET(htmlfile ${CMAKE_CURRENT_BINARY_DIR}/${rstfile_we}.html) + +        #make the html file depend on the rst file +        ADD_CUSTOM_COMMAND( +            OUTPUT ${htmlfile} DEPENDS ${rstfile} ${stylesheet} +            COMMAND ${RST2HTML} ${rstfile} ${htmlfile} ${rst2html_options} +            COMMENT "Generating ${htmlfile}" +        ) + +        #make the manual target depend on the html file +        LIST(APPEND manual_html_files ${htmlfile}) +        INSTALL(FILES ${htmlfile} DESTINATION ${PKG_DOC_DIR}/manual/html) +    ENDFOREACH(rstfile ${manual_sources}) + +    #make the html manual a build-time dependency +    ADD_CUSTOM_TARGET(manual_html ALL DEPENDS ${manual_html_files}) +ENDIF(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND") + +INSTALL(FILES ${manual_sources} DESTINATION ${PKG_DOC_DIR}/manual/rst) + +######################################################################## +# Setup Doxygen +######################################################################## +INCLUDE(FindDoxygen) + +IF(DOXYGEN_FOUND) +    MESSAGE(STATUS "  Enabled generation of Doxygen documentation.") + +    #generate the doxygen configuration file +    SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen) +    CONFIGURE_FILE( +        ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in +        ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile +    @ONLY) + +    #make doxygen directory depend on the header files +    FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp) +    ADD_CUSTOM_COMMAND( +        OUTPUT ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DEPENDS ${header_files} +        COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile +        COMMENT "Generating documentation with doxygen" +    ) + +    #make the doxygen generation a built-time dependency +    ADD_CUSTOM_TARGET(doxygen_docs ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN}) +    INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DESTINATION ${PKG_DOC_DIR}) +ELSE(DOXYGEN_FOUND) +    MESSAGE(STATUS "  Disabled generation of Doxygen documentation.") +ENDIF(DOXYGEN_FOUND) diff --git a/host/Doxyfile.in b/host/docs/Doxyfile.in index 7395516b5..7395516b5 100644 --- a/host/Doxyfile.in +++ b/host/docs/Doxyfile.in diff --git a/host/docs/build.rst b/host/docs/build.rst new file mode 100644 index 000000000..81e61475e --- /dev/null +++ b/host/docs/build.rst @@ -0,0 +1,130 @@ +======================================================================== +UHD - Build Guide +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Build Dependencies +------------------------------------------------------------------------ + +**Unix Notes:** +The dependencies can be acquired through the package manager. + +**Windows Notes:** +The dependencies can be acquired through installable exe files. +Usually, the windows installer can be found on the project's website. +Some projects do not host windows installers, and if this is the case, +follow the auxiliary download url for the windows installer (below). + +^^^^^^^^^^^^^^^^ +Git +^^^^^^^^^^^^^^^^ +Required to check out the repository. +On windows, install cygwin with git support to checkout the repository, +or install msysgit from http://code.google.com/p/msysgit/downloads/list + +^^^^^^^^^^^^^^^^ +C++ +^^^^^^^^^^^^^^^^ +On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008. +Other compilers have not been tested yet or confirmed working. + +^^^^^^^^^^^^^^^^ +CMake +^^^^^^^^^^^^^^^^ +* **Version:** at least 2.8 +* **Required for:** build time +* **Download URL:** http://www.cmake.org/cmake/resources/software.html + +^^^^^^^^^^^^^^^^ +Boost +^^^^^^^^^^^^^^^^ +* **Version:** at least 3.7 unix, at least 4.0 windows +* **Required for:** build time + run time +* **Download URL:** http://www.boost.org/users/download/ +* **Download URL (windows installer):** http://www.boostpro.com/download + +^^^^^^^^^^^^^^^^ +Python +^^^^^^^^^^^^^^^^ +* **Version:** at least 2.6 +* **Required for:** build time +* **Download URL:** http://www.python.org/download/ + +^^^^^^^^^^^^^^^^ +Cheetah +^^^^^^^^^^^^^^^^ +* **Version:** at least 2.0 +* **Required for:** build time +* **Download URL:** http://www.cheetahtemplate.org/download.html +* **Download URL (windows installer):** http://feisley.com/python/cheetah/ + +^^^^^^^^^^^^^^^^ +Doxygen +^^^^^^^^^^^^^^^^ +* **Required for:** build time (optional) +* **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc + +------------------------------------------------------------------------ +Build Instructions (Unix) +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Generate Makefiles with cmake +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:: + +    cd <uhd-repo-path>/host +    mkdir build +    cd build +    cmake ../ + +For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Build and install +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:: + +    make +    make test +    sudo make install + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the library path +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Make sure that libuhd.so is in your LD_LIBRARY_PATH +or add it to /etc/ld.so.conf and make sure to run sudo ldconfig + + +------------------------------------------------------------------------ +Build Instructions (Windows) +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Generate the project with cmake +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* Open the cmake gui program. +* Set the path to the source code: <uhd-repo-path>/host +* Set the path to the build directory: <uhd-repo-path>/host/build +* Make sure that the paths do not contain spaces. +* Click configure and select the MSVC compiler. +* Set the build variables and click configure again. +* Click generate and a project file will be created in the build directory. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Build the project in MSVC +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* Open the generated project file in MSVC. +* Select the build all target, right click, and choose build. +* Select the install target, right click, and choose build. + +**Note:** you may not have permission to build the install target. +You need to be an administrator or to run MSVC as administrator. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the PATH environment variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* Add the boost library path to %PATH% (usually c:\\program files\\boost\\<version>\\lib) +* Add the uhd library path to %PATH% (usually c:\\program files\\uhd\\lib) diff --git a/host/docs/coding.rst b/host/docs/coding.rst new file mode 100644 index 000000000..689667f30 --- /dev/null +++ b/host/docs/coding.rst @@ -0,0 +1,63 @@ +======================================================================== +UHD - Coding to the API +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Low-Level: The device API +------------------------------------------------------------------------ +A device is an abstraction for hardware that is connected to the host system. +For a USRP, this means that the motherboard and everything on it would be considered to be a "device". +The device API provides ways to: + +* Discover devices that are physical connected to the host system. +* Create a device object for a particular physical device identified by address. +* Register a device driver into the discovery and factory sub-system. +* Streaming samples with metadata into and out of the device. +* Set and get properties on the device object. + +See the documentation in device.hpp for reference. + +------------------------------------------------------------------------ +High-Level: The simple usrp +------------------------------------------------------------------------ +The goal of the simple usrp is to wrap high level functions around the device properties. +The simple usrp provides a fat interface to access the most common properties. +The simple usrp provides ways to: + +* Set and get daughterboard gains. +* Set and get daughterboard antennas. +* Set and get the streaming rates. +* Tune the DSPs and daughterboards. +* Issue stream commands. +* Set the clock configuration. +* Set the usrp time registers. +* Get the underlying device (as discussed above). + +It is recommended that users code to the simple_usrp api when possible. +See the documentation in usrp/simple_usrp.hpp for reference. + +------------------------------------------------------------------------ +Integrating custom hardware +------------------------------------------------------------------------ +Creators of custom hardware can create drivers that use the UHD API. +These drivers can be built as dynamically lodable modules that the UHD will load at runtime. +For a module to be loaded at runtime, it must be found in the UHD_MODULE_PATH environment variable. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Custom motherboard +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Create a new device driver when the driver in lib/usrp/ +cannot support your custom FPGA or hardware modifications. +Make a copy of the relevant driver code in lib/usrp/, make mods, and rename the class. +The new device code should register itself into the discovery and factory system.  + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Custom daughterboard +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Use code from an existing daughterboard in lib/usrp/dboard/* as an example. +Your daughterboard code should subclass an rx dboard, rx dboard, or xcvr dboard; +and it should respond to calls to get and set properties. +The new daughterboard code should register itself into the dboard manager +with a unique rx and/or tx 16 bit identification number. diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst new file mode 100644 index 000000000..d08b752a6 --- /dev/null +++ b/host/docs/dboards.rst @@ -0,0 +1,64 @@ +======================================================================== +UHD - Daughterboard Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Daughterboard Properties +------------------------------------------------------------------------ + +The following contains interesting notes about each daughterboard. +Eventually, this page will be expanded to list out the full +properties of each board as well. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Basic RX and and LFRX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Basic RX and LFRX boards have 3 subdevices: + +* **Subdevice A:** real signal on antenna RXA +* **Subdevice B:** real signal on antenna RXB +* **Subdevice AB:** quadrature subdevice using both antennas + +The boards have no tunable elements or programmable gains. +Though the magic of aliasing, you can down-convert signals +greater than the nyquist rate of the ADC. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Basic TX and and LFTX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Basic TX and LFTX boards have 1 quadrature subdevice using both antennas. + +The boards have no tunable elements or programmable gains. +Though the magic of aliasing, you can up-convert signals +greater than the nyquist rate of the DAC. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +RFX Series +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Transmit Antennas: **TX/RX** + +Receive Antennas: **TX/RX** or **RX2** + +The user may set the receive antenna to be TX/RX or RX2. +However, when using an RFX board in full-duplex mode, +the receive antenna will always be set to RX2, regardless of the settings. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +XCVR 2450 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The XCVR2450 has a non-contiguous tuning range consiting of a high band and a low band. +The high band consists of frequencies between...TODO + +Transmit Antennas: **J1** or **J2** + +Receive Antennas: **J1** or **J2** + +When using the XCVR2450 in full-duplex mode, +the user must set the receive antenna and the transmit antenna to be different; +not doing so will yeild undefined results. + +The XCVR2450 uses a common LO for both receive and transmit. +Even though the API allows the RX and TX LOs to be individually set, +a change of one LO setting will be reflected in the other LO setting. diff --git a/host/docs/index.rst b/host/docs/index.rst new file mode 100644 index 000000000..3dc7a2d98 --- /dev/null +++ b/host/docs/index.rst @@ -0,0 +1,31 @@ +======================================================================== +UHD - Universal Hardware Driver +======================================================================== + +The UHD is the universal hardware driver for Ettus Research products. +The goal of the UHD is to provide a host driver and api for current and future Ettus Research products. +Users will be able to use the UHD driver standalone/without gnuradio. +Also, a dual license option will be available for those who build against the UHD +but cannot release their software products under the GPL. + +------------------------------------------------------------------------ +Contents +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^ +Building the UHD +^^^^^^^^^^^^^^^^^^^^^ +* `Build Guide <./build.html>`_ + +^^^^^^^^^^^^^^^^^^^^^ +Supported Devices +^^^^^^^^^^^^^^^^^^^^^ +* `USRP2 App Notes <./usrp2.html>`_ +* `Daughterboard App Notes <./dboards.html>`_ + +^^^^^^^^^^^^^^^^^^^^^ +API Documentation +^^^^^^^^^^^^^^^^^^^^^ +* `Doxygen <./../../doxygen/html/index.html>`_ +* `Using the API <./coding.html>`_ + diff --git a/host/docs/style.css b/host/docs/style.css new file mode 100644 index 000000000..bf97bf007 --- /dev/null +++ b/host/docs/style.css @@ -0,0 +1,102 @@ +body{ +font-family:Arial, Helvetica, sans-serif; +font-size:11pt; +color:black; +background-color:white; +width:90%; +margin:0 auto 0 auto; +} + +div.document div.contents{ +border:1px solid #333333; +padding:10px 30px 10px 10px; +margin-left:50px; +color:inherit; +background-color:#FCFCFC; +display:inline-block; +} + +div.document p.topic-title{ +font-weight:bold; +} + +div.document a:link, div.document a:visited{ +color:#236B8E; +background-color:inherit; +text-decoration:none; +} + +div.document a:hover{ +color:#4985D6; +background-color:inherit; +text-decoration:none; +} + +div.document h1.title{ +font-size:150%; +border-left:1px solid #333333; +border-bottom:1px solid #333333; +text-align:left; +padding:10px 0px 10px 10px; +margin:10px 5px 20px 5px; +color:#333333; +background-color:inherit; +} + +div.document h2.subtitle, div.section h1{ +margin-top:50px; +border-bottom:1px solid #333333; +font-size:140%; +text-align:center; +padding:20px 0px 10px 0px; +color:#333333; +background-color:inherit; +} + +div.section h2{ +font-size:110%; +text-align:left; +padding:15px 0px 5px 0px; +text-decoration:underline; +color:#333333; +background-color:inherit; +} + +div.document pre.literal-block{ +border:1px inset #333333; +padding:5px; +margin:10px 5px 10px 5px; +color:inherit; +background-color:#FCFCFC; +font-size:90%; +} + +div.document table{ +padding:5px; +font-size:95%; +} + +div.document th{ +padding:3px 7px 3px 7px; +border:1px solid #333333; +text-align:center; +color:inherit; +background-color:#ECECEC; +} + +div.document tr{ +} + +div.document td{ +padding:3px 7px 3px 7px; +border:1px solid #333333; +text-align:center; +color:inherit; +background-color:#FCFCFC; +} + +div.footer{ +margin:50px auto 30px auto; +text-align:center; +font-size:85%; +} diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst new file mode 100644 index 000000000..092332442 --- /dev/null +++ b/host/docs/usrp2.rst @@ -0,0 +1,128 @@ +======================================================================== +UHD - USRP2 Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Building firmware and FPGA images +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^ +FPGA Image +^^^^^^^^^^^^^^^^^^ +Xilinx ISE 10.1 is required to build the FPGA image for the USRP2 +(newer version of ISE are known to build buggy images). +The build requires that you have a unix-like environment with make. +Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH. + +Run the following commands: +:: + +    cd <uhd-repo-path>/fpga/usrp2/top/u2_rev3 +    make bin + +*The image file will be ./build/u2_rev3.bin* + +^^^^^^^^^^^^^^^^^^ +Firmware Image +^^^^^^^^^^^^^^^^^^ +The Microblaze GCC compiler from the Xilinx EDK is required to build the firmware. +The build requires that you have a unix-like environment with autotools and make. +Make sure that mb-gcc from the Xilinx EDK/microblaze directory is in your $PATH. + +Run the following commands: +:: + +    cd <uhd-repo-path>/firmware/microblaze +    ./boostrap +    ./configure --host=mb +    make + +*The image file will be ./apps/txrx_uhd.bin* + +------------------------------------------------------------------------ +Load the images onto the SD card +------------------------------------------------------------------------ +**Warning!** +Use the u2_flash_tool with caution. If you specify the wrong device node, +you could overwrite your hard drive. Make sure that --dev= specifies the SD card. + +Load the FPGA image: + +:: + +    cd <uhd-repo-path>/firmware/microblaze +    sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t fpga -w <path_to_fpga_image> + +Load the firmware image: + +:: + +    cd <uhd-repo-path>/firmware/microblaze directory +    sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t s/w -w <path_to_firmware_image> + +------------------------------------------------------------------------ +Setup networking +------------------------------------------------------------------------ +The USRP2 only supports gigabit ethernet, and +will not work with a 10/100 Mbps interface. +Because the USRP2 uses gigabit ethernet pause frames for flow control, +you cannot use multiple USRP2s with a switch or a hub. +It is recommended that each USRP2 be plugged directly into its own +dedicated gigabit ethernet interface on the host computer. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the host interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The USRP2 communicates at the IP/UDP layer over the gigabit ethernet. +The default IP address of the USRP2 is **192.168.10.2** +You will need to configure the host's ethernet interface with a static IP address to enable communication. +An address of **192.168.10.1** is recommended. + +**Note:** +When using the UHD, if an IP address for the USRP2 is not specified, +the software will use UDP broadcast packets to locate the USRP2. +On some systems, the firewall will block UDP broadcast packets. +It is recommended that you change or disable your firewall settings.  + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Change the USRP2's IP address +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You may need to change the USRP2's IP address for several reasons: + +* to satisfy your particular network configuration +* to use multiple USRP2s on the same host computer +* to set a known IP address into USRP2 (in case you forgot) + +**Method 1:** +To change the USRP2's IP address +you must know the current address of the USRP2, +and the network must be setup properly as described above. +Run the following commands: +:: + +    cd <prefix>/share/uhd/utils +    ./usrp_burner --addr=192.168.10.2 --new-ip=192.168.10.3 + +**Method 2 (Linux Only):** +This method assumes that you do not know the IP address of your USRP2. +It uses raw ethernet packets to bypass the IP/UDP layer to communicate with the USRP2. +Run the following commands: +:: + +    cd <prefix>/share/uhd/utils +    ./usrp2_recovery.py --ifc=eth0 --new-ip=192.168.10.3 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Debugging networking problems +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +**Monitor the USRP2:** +You can read the serial port on the rear of the USRP2 +to get debug verbose from the embedded microcontroller. +Use a standard USB to tty-level serial converter at 230400 baud. +The microcontroller prints useful information about IP addresses, +MAC addresses, control packets, and fast-path settings. + +**Monitor the host network traffic:** +Use wireshark to monitor packets sent to and received from the USRP2. diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index d49f7d182..4b8774036 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -26,7 +26,7 @@ namespace po = boost::program_options;  int UHD_SAFE_MAIN(int argc, char *argv[]){      //variables to be set by po -    std::string transport_args; +    std::string args;      int seconds_in_future;      size_t total_num_samps;      double rx_rate; @@ -35,7 +35,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address 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")          ("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples") @@ -52,9 +52,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //create a usrp device      std::cout << std::endl; -    std::cout << boost::format("Creating the usrp device with: %s...") -        % transport_args << std::endl; -    uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(transport_args); +    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; +    uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);      uhd::device::sptr dev = sdev->get_device();      std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index e4cdf2cef..dbce21c98 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -25,6 +25,7 @@ INSTALL(FILES      metadata.hpp      otw_type.hpp      ranges.hpp +    serial.hpp      stream_cmd.hpp      time_spec.hpp      tune_result.hpp diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp index f5dd9371c..e8da2a1ab 100644 --- a/host/include/uhd/types/device_addr.hpp +++ b/host/include/uhd/types/device_addr.hpp @@ -32,13 +32,23 @@ namespace uhd{       *       * 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] +     * - 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. +     * +     * An arguments string, is a way to represent a device address +     * using a single string with delimiter characters. +     * - Ex: addr=192.168.10.2 +     * - Ex: addr=192.168.10.2, rx_buff_size=1e6       */      class UHD_API device_addr_t : public dict<std::string, std::string>{      public: +        /*! +         * Create a device address from an args string. +         * \param args the arguments string +         */ +        device_addr_t(const std::string &args = "");          /*!           * Convert a device address into a printable string. @@ -52,14 +62,6 @@ namespace uhd{           * \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 diff --git a/host/include/uhd/types/io_type.hpp b/host/include/uhd/types/io_type.hpp index 930394d1b..5176374d6 100644 --- a/host/include/uhd/types/io_type.hpp +++ b/host/include/uhd/types/io_type.hpp @@ -23,6 +23,7 @@  namespace uhd{      /*! +     * The Input/Output configuration struct:       * Used to specify the IO type with device send/recv.       */      class UHD_API io_type_t{ diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp index d93b38b50..55add71cc 100644 --- a/host/include/uhd/types/metadata.hpp +++ b/host/include/uhd/types/metadata.hpp @@ -70,7 +70,10 @@ namespace uhd{           * Timed-out on receive?           */ -        //default constructor +        /*! +         * The default constructor: +         * Sets the fields to default values (flags set to false). +         */          rx_metadata_t(void);      }; @@ -103,7 +106,10 @@ namespace uhd{          bool start_of_burst;          bool end_of_burst; -        //default constructor +        /*! +         * The default constructor: +         * Sets the fields to default values (flags set to false). +         */          tx_metadata_t(void);      }; diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp new file mode 100644 index 000000000..c134725f5 --- /dev/null +++ b/host/include/uhd/types/serial.hpp @@ -0,0 +1,122 @@ +// +// 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_SERIAL_HPP +#define INCLUDED_UHD_TYPES_SERIAL_HPP + +#include <uhd/config.hpp> +#include <boost/cstdint.hpp> +#include <vector> + +namespace uhd{ + +    /*! +     * Byte vector typedef for passing data in and out of I2C interfaces. +     */ +    typedef std::vector<boost::uint8_t> byte_vector_t; + +    /*! +     * The i2c interface class: +     * Provides i2c and eeprom functionality. +     * A subclass should only have to implement the i2c routines. +     * An eeprom implementation comes for free with the interface. +     * +     * The eeprom routines are implemented on top of i2c. +     * The built in eeprom implementation only does single +     * byte reads and byte writes over the i2c interface, +     * so it should be portable across multiple eeproms. +     * Override the eeprom routines if this is not acceptable. +     */ +    class UHD_API i2c_iface{ +    public: +        /*! +         * Write bytes over the i2c. +         * \param addr the address +         * \param buf the vector of bytes +         */ +        virtual void write_i2c( +            boost::uint8_t addr, +            const byte_vector_t &buf +        ) = 0; + +        /*! +         * Read bytes over the i2c. +         * \param addr the address +         * \param num_bytes number of bytes to read +         * \return a vector of bytes +         */ +        virtual byte_vector_t read_i2c( +            boost::uint8_t addr, +            size_t num_bytes +        ) = 0; + +        /*! +         * Write bytes to an eeprom. +         * \param addr the address +         * \param offset byte offset +         * \param buf the vector of bytes +         */ +        virtual void write_eeprom( +            boost::uint8_t addr, +            boost::uint8_t offset, +            const byte_vector_t &buf +        ); + +        /*! +         * Read bytes from an eeprom. +         * \param addr the address +         * \param offset byte offset +         * \param num_bytes number of bytes to read +         * \return a vector of bytes +         */ +        virtual byte_vector_t read_eeprom( +            boost::uint8_t addr, +            boost::uint8_t offset, +            size_t num_bytes +        ); +    }; + +    /*! +     * The SPI configuration struct: +     * Used to configure a SPI transaction interface. +     */ +    struct UHD_API spi_config_t{ +        /*! +         * The edge type specifies when data is valid +         * relative to the edge of the serial clock. +         */ +        enum edge_t{ +            EDGE_RISE = 'r', +            EDGE_FALL = 'f' +        }; + +        //! on what edge is the mosi data valid? +        edge_t mosi_edge; + +        //! on what edge is the miso data valid? +        edge_t miso_edge; + +        /*! +         * Create a new spi config. +         * \param edge the default edge for mosi and miso +         */ +        spi_config_t(edge_t edge = EDGE_RISE); +    }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_SERIAL_HPP */ diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index f06d27118..25d9e41d0 100644 --- a/host/include/uhd/types/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -28,10 +28,19 @@ namespace uhd{       * The time_spec_t can be used when setting the time on devices,       * and for dealing with time stamped samples though the metadata.       * and for controlling the start of streaming for applicable dsps. +     * +     * The fractional seconds are represented in units of nanoseconds, +     * which provide a clock-domain independent unit of time storage. +     * The methods "get_ticks" and "set_ticks" can be used to convert +     * the fractional seconds to and from clock-domain specific units. +     * +     * The nanoseconds count is stored as double precision floating point. +     * This gives the fractional seconds enough precision to unambiguously +     * specify a clock-tick/sample-count up to rates of several petahertz.       */      struct UHD_API time_spec_t{ -        //! whole seconds count +        //! whole/integer seconds count in seconds          boost::uint32_t secs;          //! fractional seconds count in nano-seconds @@ -39,24 +48,26 @@ namespace uhd{          /*!           * Convert the fractional nsecs to clock ticks. +         * Translation into clock-domain specific units.           * \param tick_rate the number of ticks per second -         * \return the number of ticks in this time spec +         * \return the fractional seconds tick count           */          boost::uint32_t get_ticks(double tick_rate) const;          /*!           * Set the fractional nsecs from clock ticks. +         * Translation from clock-domain specific units.           * \param ticks the fractional seconds tick count           * \param tick_rate the number of ticks per second           */          void set_ticks(boost::uint32_t ticks, double tick_rate);          /*! -         * Create a time_spec_t from seconds and ticks. -         * \param new_secs the new seconds (default = 0) -         * \param new_nsecs the new nano-seconds (default = 0) +         * Create a time_spec_t from whole and fractional seconds. +         * \param secs the whole/integer seconds count in seconds (default = 0) +         * \param nsecs the fractional seconds count in nanoseconds (default = 0)           */ -        time_spec_t(boost::uint32_t new_secs = 0, double new_nsecs = 0); +        time_spec_t(boost::uint32_t secs = 0, double nsecs = 0);      }; diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 4b880308e..ff2636d8c 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES      #### dboard headers ###      dboard_base.hpp +    dboard_eeprom.hpp      dboard_id.hpp      dboard_iface.hpp      dboard_manager.hpp diff --git a/host/include/uhd/usrp/dboard_eeprom.hpp b/host/include/uhd/usrp/dboard_eeprom.hpp new file mode 100644 index 000000000..108027b46 --- /dev/null +++ b/host/include/uhd/usrp/dboard_eeprom.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_USRP_DBOARD_EEPROM_HPP +#define INCLUDED_UHD_USRP_DBOARD_EEPROM_HPP + +#include <uhd/config.hpp> +#include <uhd/usrp/dboard_id.hpp> +#include <uhd/types/serial.hpp> +#include <string> + +namespace uhd{ namespace usrp{ + +struct UHD_API dboard_eeprom_t{ +    /*! +     * The dboard id that was read from eeprom or will be set to eeprom. +     */ +    dboard_id_t id; + +    /*! +     * Create a dboard eeprom struct from the bytes read out of eeprom. +     * The constructor will parse out the dboard id from a vector of bytes. +     * To be valid, the bytes vector should be at least num_bytes() long. +     * If the parsing fails due to bad checksum or incomplete length, +     * the dboard id in this struct will be set to dboard_id::NONE. +     * \param bytes the vector of bytes +     */ +    dboard_eeprom_t(const uhd::byte_vector_t &bytes = uhd::byte_vector_t(0)); + +    /*! +     * Get the bytes that would be written to dboard eeprom. +     * \return a vector of bytes +     */ +    uhd::byte_vector_t get_eeprom_bytes(void); + +    /*! +     * Get the number of bytes in the dboard eeprom segment. +     * Use this value when reading out of the dboard eeprom. +     * \return the number of bytes used by dboard eeprom +     */ +    static size_t num_bytes(void); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_DBOARD_EEPROM_HPP */ diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index 71c7be200..1214a1a2f 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -19,39 +19,12 @@  #define INCLUDED_UHD_USRP_DBOARD_IFACE_HPP  #include <uhd/config.hpp> +#include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/cstdint.hpp> -#include <vector>  namespace uhd{ namespace usrp{ -//spi configuration struct -struct UHD_API spi_config_t{ -    /*! -     * The edge type specifies when data is valid -     * relative to the edge of the serial clock. -     */ -    enum edge_t{ -        EDGE_RISE = 'r', -        EDGE_FALL = 'f' -    }; - -    //! on what edge is the mosi data valid? -    edge_t mosi_edge; - -    //! on what edge is the miso data valid? -    edge_t miso_edge; - -    /*! -     * Create a new spi config. -     * \param edge the default edge for mosi and miso -     */ -    spi_config_t(edge_t edge = EDGE_RISE){ -        mosi_edge = edge; -        miso_edge = edge; -    } -}; -  /*!   * The daughter board dboard interface to be subclassed.   * A dboard instance interfaces with the mboard though this api. @@ -61,7 +34,6 @@ struct UHD_API spi_config_t{  class UHD_API dboard_iface{  public:      typedef boost::shared_ptr<dboard_iface> sptr; -    typedef std::vector<boost::uint8_t> byte_vector_t;      //tells the host which unit to use      enum unit_t{ @@ -123,19 +95,19 @@ public:      /*!       * Write to an I2C peripheral.       * -     * \param i2c_addr I2C bus address (7-bits) -     * \param buf the data to write +     * \param addr I2C bus address (7-bits) +     * \param bytes the data to write       */ -    virtual void write_i2c(int i2c_addr, const byte_vector_t &buf) = 0; +    virtual void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) = 0;      /*!       * Read from an I2C peripheral.       * -     * \param i2c_addr I2C bus address (7-bits) +     * \param addr I2C bus address (7-bits)       * \param num_bytes number of bytes to read       * \return the data read if successful, else a zero length string.       */ -    virtual byte_vector_t read_i2c(int i2c_addr, size_t num_bytes) = 0; +    virtual byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) = 0;      /*!       * Write data to SPI bus peripheral. diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index 6de64b02d..007d85bb4 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -33,7 +33,6 @@ namespace uhd{ namespace usrp{   * Provide wax::obj access to the subdevs inside.   */  class UHD_API dboard_manager : boost::noncopyable{ -  public:      typedef boost::shared_ptr<dboard_manager> sptr; diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp index 3b290319f..0208a6c2c 100644 --- a/host/include/uhd/usrp/dboard_props.hpp +++ b/host/include/uhd/usrp/dboard_props.hpp @@ -29,7 +29,8 @@ namespace uhd{ namespace usrp{          DBOARD_PROP_NAME         = 'n', //ro, std::string          DBOARD_PROP_SUBDEV       = 's', //ro, wax::obj          DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t -        DBOARD_PROP_USED_SUBDEVS = 'u'  //ro, prop_names_t +        DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t +        DBOARD_PROP_DBOARD_ID    = 'i'  //rw, dboard_id_t          //DBOARD_PROP_CODEC              //ro, wax::obj //----> not sure, dont have to deal with yet      };  diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index c4e0338f7..c4142b4e6 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -39,20 +39,72 @@ namespace uhd{ namespace usrp{  class UHD_API simple_usrp : boost::noncopyable{  public:      typedef boost::shared_ptr<simple_usrp> sptr; -    static sptr make(const std::string &args); +    /*! +     * Make a new simple usrp from the device address. +     * \param dev_addr the device address +     * \return a new simple usrp object +     */ +    static sptr make(const device_addr_t &dev_addr); + +    /*! +     * Get the underlying device object. +     * This is needed to get access to the streaming API and properties. +     * \return the device object within this simple usrp +     */      virtual device::sptr get_device(void) = 0; +    /*! +     * Get a printable name for this simple usrp. +     * \return a printable string +     */      virtual std::string get_name(void) = 0;      /*******************************************************************       * Misc       ******************************************************************/ +    /*! +     * Sets the time registers on the usrp immediately. +     * \param time_spec the time to latch into the usrp device +     */      virtual void set_time_now(const time_spec_t &time_spec) = 0; + +    /*! +     * Set the time registers on the usrp at the next pps tick. +     * The values will not be latched in until the pulse occurs. +     * It is recommended that the user sleep(1) after calling to ensure +     * that the time registers will be in a known state prior to use. +     * +     * Note: Because this call sets the time on the "next" pps, +     * the seconds in the time spec should be current seconds + 1. +     * +     * \param time_spec the time to latch into the usrp device +     */      virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + +    /*! +     * Issue a stream command to the usrp device. +     * This tells the usrp to send samples into the host. +     * See the documentation for stream_cmd_t for more info. +     * \param stream_cmd the stream command to issue +     */      virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + +    /*! +     * Set the clock configuration for the usrp device. +     * This tells the usrp how to get a 10Mhz reference and PPS clock. +     * See the documentation for clock_config_t for more info. +     * \param clock_config the clock configuration to set +     */      virtual void set_clock_config(const clock_config_t &clock_config) = 0; +    /*! +     * Read the RSSI value from a usrp device. +     * Or throw if the dboard does not support an RSSI readback. +     * \return the rssi in dB +     */ +    virtual float read_rssi(void) = 0; +      /*******************************************************************       * RX methods       ******************************************************************/ @@ -70,6 +122,8 @@ public:      virtual std::string get_rx_antenna(void) = 0;      virtual std::vector<std::string> get_rx_antennas(void) = 0; +    virtual bool get_rx_lo_locked(void) = 0; +      /*******************************************************************       * TX methods       ******************************************************************/ @@ -86,6 +140,8 @@ public:      virtual void set_tx_antenna(const std::string &ant) = 0;      virtual std::string get_tx_antenna(void) = 0;      virtual std::vector<std::string> get_tx_antennas(void) = 0; + +    virtual bool get_tx_lo_locked(void) = 0;  };  }} diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp index cd6b14ef5..1f8e91d68 100644 --- a/host/include/uhd/usrp/subdev_props.hpp +++ b/host/include/uhd/usrp/subdev_props.hpp @@ -35,13 +35,13 @@ namespace uhd{ namespace usrp{          SUBDEV_PROP_FREQ_RANGE        = 'F', //ro, freq_range_t          SUBDEV_PROP_ANTENNA           = 'a', //rw, std::string          SUBDEV_PROP_ANTENNA_NAMES     = 'A', //ro, prop_names_t -        //SUBDEV_PROP_ENABLED           = 'e', //rw, bool //---> dont need, we have atr +        SUBDEV_PROP_LO_LOCKED         = 'L', //ro, bool          SUBDEV_PROP_QUADRATURE        = 'q', //ro, bool          SUBDEV_PROP_IQ_SWAPPED        = 'i', //ro, bool          SUBDEV_PROP_SPECTRUM_INVERTED = 's', //ro, bool -        SUBDEV_PROP_USE_LO_OFFSET     = 'l'  //ro, bool -        //SUBDEV_PROP_RSSI,              //ro, float //----> not on all boards, use named prop -        //SUBDEV_PROP_BANDWIDTH          //rw, double //----> not on all boards, use named prop +        SUBDEV_PROP_USE_LO_OFFSET     = 'l', //ro, bool +        SUBDEV_PROP_RSSI              = 'R', //ro, float +        SUBDEV_PROP_BANDWIDTH         = 'B'  //rw, double      };  }} //namespace diff --git a/host/include/uhd/utils/assert.hpp b/host/include/uhd/utils/assert.hpp index 842ed8dfa..01beed757 100644 --- a/host/include/uhd/utils/assert.hpp +++ b/host/include/uhd/utils/assert.hpp @@ -18,27 +18,27 @@  #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 <boost/throw_exception.hpp> +#include <boost/exception/info.hpp>  #include <stdexcept> +#include <string>  namespace uhd{ -    class assert_error : public std::logic_error{ -    public: -        explicit assert_error(const std::string& what_arg) : logic_error(what_arg){ -            /* NOP */ -        } -    }; +    //! The exception to throw when assertions fail +    struct UHD_API assert_error : virtual std::exception, virtual boost::exception{}; -    #define ASSERT_THROW(_x) if (not (_x)) { \ -        throw uhd::assert_error(str(boost::format( \ -            "Assertion Failed:\n  %s:%d\n  %s\n  ---> %s <---" \ -        ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ -    } +    //! The assertion info, the code that failed +    typedef boost::error_info<struct tag_assert_info, std::string> assert_info; + +    //! Throw an assert error with throw-site information +    #define UHD_ASSERT_THROW(_x) if (not (_x)) \ +        BOOST_THROW_EXCEPTION(uhd::assert_error() << uhd::assert_info(#_x))      /*!       * Check that an element is found in a container. @@ -58,17 +58,18 @@ namespace uhd{      ){          if (std::has(iterable, elem)) return;          std::string possible_values = ""; -        BOOST_FOREACH(T e, iterable){ -            if (e != iterable.begin()[0]) possible_values += ", "; +        size_t i = 0; +        BOOST_FOREACH(const T &e, iterable){ +            if (i++ > 0) possible_values += ", ";              possible_values += boost::lexical_cast<std::string>(e);          } -        throw uhd::assert_error(str(boost::format( +        boost::throw_exception(uhd::assert_error() << assert_info(str(boost::format(                  "Error: %s is not a valid %s. "                  "Possible values are: [%s]."              )              % boost::lexical_cast<std::string>(elem)              % what % possible_values -        )); +        )));      }  }//namespace uhd diff --git a/host/include/uhd/utils/props.hpp b/host/include/uhd/utils/props.hpp index 6be0b2ce5..516102a5f 100644 --- a/host/include/uhd/utils/props.hpp +++ b/host/include/uhd/utils/props.hpp @@ -21,27 +21,63 @@  #include <uhd/config.hpp>  #include <uhd/wax.hpp>  #include <boost/tuple/tuple.hpp> +#include <boost/throw_exception.hpp> +#include <boost/exception/info.hpp> +#include <stdexcept>  #include <vector>  #include <string>  namespace uhd{ -    //typedef for handling named properties +    //! The type for a vector of property names      typedef std::vector<std::string> prop_names_t; -    typedef boost::tuple<wax::obj, std::string> named_prop_t; + +    /*! +     * A named prop struct holds a key and a name. +     * Allows properties to be sub-sectioned by name. +     */ +    struct UHD_API named_prop_t{ +        wax::obj key; +        std::string name; + +        /*! +         * Create a new named prop from key and name. +         * \param key the property key +         * \param name the string name +         */ +        named_prop_t(const wax::obj &key, const std::string &name); +    };      /*!       * Utility function to separate a named property into its components.       * \param key a reference to the prop object       * \param name a reference to the name object +     * \return a tuple that can be used with boost::tie +     */ +    UHD_API boost::tuple<wax::obj, std::string> extract_named_prop( +        const wax::obj &key, +        const std::string &name = "" +    ); + +    //! The exception to throw for property errors +    struct UHD_API prop_error : virtual std::exception, virtual boost::exception{}; + +    //! The property error info (verbose or message) +    typedef boost::error_info<struct tag_prop_info, std::string> prop_info; + +    /*! +     * Throw when getting a not-implemented or write-only property. +     * Throw-site information will be included with this error. +     */ +    #define UHD_THROW_PROP_GET_ERROR() \ +        BOOST_THROW_EXCEPTION(uhd::prop_error() << uhd::prop_info("cannot get this property")) + +    /*! +     * Throw when setting a not-implemented or read-only property. +     * Throw-site information will be included with this error.       */ -    inline UHD_API named_prop_t //must be exported as part of the api to work (TODO move guts to cpp file) -    extract_named_prop(const wax::obj &key, const std::string &name = ""){ -        if (key.type() == typeid(named_prop_t)){ -            return key.as<named_prop_t>(); -        } -        return named_prop_t(key, name); -    } +    #define UHD_THROW_PROP_SET_ERROR() \ +        BOOST_THROW_EXCEPTION(uhd::prop_error() << uhd::prop_info("cannot set this property"))  } //namespace uhd diff --git a/host/include/uhd/utils/safe_main.hpp b/host/include/uhd/utils/safe_main.hpp index b682aa540..a4e4e06e8 100644 --- a/host/include/uhd/utils/safe_main.hpp +++ b/host/include/uhd/utils/safe_main.hpp @@ -19,6 +19,7 @@  #define INCLUDED_UHD_UTILS_SAFE_MAIN_HPP  #include <uhd/config.hpp> +#include <boost/exception/diagnostic_information.hpp>  #include <iostream>  #include <stdexcept> @@ -33,6 +34,8 @@  int main(int argc, char *argv[]){ \      try { \          return _main(argc, argv); \ +    } catch(const boost::exception &e){ \ +        std::cerr << "Error: " << boost::diagnostic_information(e) << std::endl; \      } catch(const std::exception &e) { \          std::cerr << "Error: " << e.what() << std::endl; \      } catch(...) { \ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index ff7f2c0df..48fee5a80 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -50,13 +50,13 @@ SET(libuhd_sources      gain_handler.cpp      load_modules.cpp      types.cpp +    utils.cpp      wax.cpp      transport/convert_types.cpp      transport/if_addrs.cpp      transport/udp_simple.cpp -    usrp/dboard/db_basic_and_lf.cpp -    usrp/dboard/db_rfx.cpp      usrp/dboard_base.cpp +    usrp/dboard_eeprom.cpp      usrp/simple_usrp.cpp      usrp/dboard_manager.cpp      usrp/tune_helper.cpp @@ -66,11 +66,18 @@ SET(libuhd_sources  # Generate Files  ########################################################################  MACRO(UHD_PYTHON_GEN_SOURCE_FILE pyfile outfile) +    #ensure that the directory exists for outfile +    GET_FILENAME_COMPONENT(outfile_dir ${outfile} PATH) +    FILE(MAKE_DIRECTORY ${outfile_dir}) + +    #make the outfile depend on the python script      ADD_CUSTOM_COMMAND(          OUTPUT ${outfile} DEPENDS ${pyfile}          COMMAND ${PYTHON_EXECUTABLE} ${pyfile} ${outfile} -        COMMENT "Calling ${pyfile} to generate ${outfile}" +        COMMENT "Generating ${outfile}"      ) + +    #make libuhd depend on the outfile      LIST(APPEND libuhd_sources ${outfile})  ENDMACRO(UHD_PYTHON_GEN_SOURCE_FILE) @@ -96,6 +103,29 @@ UHD_PYTHON_GEN_SOURCE_FILE(      ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9777_regs.hpp  ) +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad5624_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad5624_regs.hpp +) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad7922_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad7922_regs.hpp +) + +UHD_PYTHON_GEN_SOURCE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_max2829_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/max2829_regs.hpp +) + +######################################################################## +# Add dboard sources +######################################################################## +LIST(APPEND libuhd_sources +    usrp/dboard/db_basic_and_lf.cpp +    usrp/dboard/db_rfx.cpp +    usrp/dboard/db_xcvr2450.cpp +)  ########################################################################  # Add usrp2 sources diff --git a/host/lib/device.cpp b/host/lib/device.cpp index 0197a6232..706f64951 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -132,8 +132,8 @@ device::sptr device::make(const device_addr_t &hint, size_t which){      //try to find an existing device      try{ -        ASSERT_THROW(hash_to_device.has_key(dev_hash)); -        ASSERT_THROW(not hash_to_device[dev_hash].expired()); +        UHD_ASSERT_THROW(hash_to_device.has_key(dev_hash)); +        UHD_ASSERT_THROW(not hash_to_device[dev_hash].expired());          return hash_to_device[dev_hash].lock();      }      //create and register a new device diff --git a/host/lib/ic_reg_maps/.gitignore b/host/lib/ic_reg_maps/.gitignore new file mode 100644 index 000000000..a74b07aee --- /dev/null +++ b/host/lib/ic_reg_maps/.gitignore @@ -0,0 +1 @@ +/*.pyc diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py new file mode 100644 index 000000000..d05470706 --- /dev/null +++ b/host/lib/ic_reg_maps/common.py @@ -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/>. +# + +import re +import math +from Cheetah.Template import Template + +def parse_tmpl(_tmpl_text, **kwargs): +    return str(Template(_tmpl_text, kwargs)) + +class reg: +    def __init__(self, reg_des): +        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) +        name, addr, bit_range, default, enums = x.groups() + +        #store variables +        self._name = name +        self._addr = int(addr, 16) +        if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':'))) +        else: self._addr_spec = int(bit_range), int(bit_range) +        self._default = int(default, 16) + +        #extract enum +        self._enums = list() +        if enums: +            enum_val = 0 +            for enum_str in map(str.strip, enums.split(',')): +                if '=' in enum_str: +                    enum_name, enum_val = enum_str.split('=') +                    enum_val = int(enum_val) +                else: enum_name = enum_str +                self._enums.append((enum_name, enum_val)) +                enum_val += 1 + +    def get_addr(self): return self._addr +    def get_enums(self): return self._enums +    def get_name(self): return self._name +    def get_default(self): +        for key, val in self.get_enums(): +            if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) +        return self._default +    def get_stdint_type(self):\ +        return 'uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8) +    def get_shift(self): return self._addr_spec[0] +    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) +    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 diff --git a/host/lib/ic_reg_maps/gen_ad5624_regs.py b/host/lib/ic_reg_maps/gen_ad5624_regs.py new file mode 100755 index 000000000..9e8ae5be5 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_ad5624_regs.py @@ -0,0 +1,82 @@ +#!/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/>. +# + +import sys +from common import * + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +data             0[4:15]           0 +addr             0[16:18]          0       DAC_A=0, DAC_B=1, DAC_C=2, DAC_D=3, ALL=7 +cmd              0[19:21]          0       wr_input_n, up_dac_n, wr_input_n_up_all, wr_up_dac_chan_n, power_down, reset, load_ldac +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_AD5624_REGS_HPP +\#define INCLUDED_AD5624_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct ad5624_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #for $i, $enum in enumerate($reg.get_enums()) +        #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' +        $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma +        #end for +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    ad5624_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    boost::uint32_t get_reg(void){ +        boost::uint32_t reg = 0; +        #for $reg in filter(lambda r: r.get_addr() == 0, $regs) +        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +        #end for +        return reg; +    } + +}; + +\#endif /* INCLUDED_AD5624_REGS_HPP */ +""" + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_ad7922_regs.py b/host/lib/ic_reg_maps/gen_ad7922_regs.py new file mode 100755 index 000000000..23f28c0da --- /dev/null +++ b/host/lib/ic_reg_maps/gen_ad7922_regs.py @@ -0,0 +1,88 @@ +#!/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/>. +# + +import sys +from common import * + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +result           0[0:11]        0 +mod              0[12]          0 +chn              0[13]          0 +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_AD7922_REGS_HPP +\#define INCLUDED_AD7922_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct ad7922_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #for $i, $enum in enumerate($reg.get_enums()) +        #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' +        $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma +        #end for +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    ad7922_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    boost::uint16_t get_reg(void){ +        boost::uint16_t reg = 0; +        #for $reg in filter(lambda r: r.get_addr() == 0, $regs) +        reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +        #end for +        return reg; +    } + +    void set_reg(boost::uint16_t reg){ +        #for $reg in filter(lambda r: r.get_addr() == 0, $regs) +        $reg.get_name() = (reg >> $reg.get_shift()) & $reg.get_mask(); +        #end for +    } + +}; + +\#endif /* INCLUDED_AD7922_REGS_HPP */ +""" + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py index 90230b8f9..2dc19c691 100755 --- a/host/lib/ic_reg_maps/gen_ad9510_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py @@ -1,32 +1,23 @@  #!/usr/bin/env python  # -# Copyright 2008,2009 Free Software Foundation, Inc. -#  -# This file is part of GNU Radio -#  -# GNU Radio is free software; you can redistribute it and/or modify +# 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 asversion 3, or (at your option) -# any later version. -#  -# GNU Radio is distributed in the hope that it will be useful, +# 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 GNU Radio; see the file COPYING.  If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# -import re -import os  import sys -from Cheetah.Template import Template -def parse_tmpl(_tmpl_text, **kwargs): -    return str(Template(_tmpl_text, kwargs)) -def safe_makedirs(path): -    not os.path.isdir(path) and os.makedirs(path) +from common import *  ########################################################################  # Template for raw text data describing registers @@ -177,48 +168,6 @@ struct ad9510_regs_t{  \#endif /* INCLUDED_AD9510_REGS_HPP */  """ -class reg: -    def __init__(self, reg_des): -        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) -        name, addr, bit_range, default, enums = x.groups() - -        #store variables -        self._name = name -        self._addr = int(addr, 16) -        if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':')) -        else: self._addr_spec = int(bit_range), int(bit_range) -        self._default = int(default, 16) - -        #extract enum -        self._enums = list() -        if enums: -            enum_val = 0 -            for enum_str in map(str.strip, enums.split(',')): -                if '=' in enum_str: -                    enum_name, enum_val = enum_str.split('=') -                    enum_val = int(enum_val) -                else: enum_name = enum_str -                self._enums.append((enum_name, enum_val)) -                enum_val += 1 - -    def get_addr(self): return self._addr -    def get_enums(self): return self._enums -    def get_name(self): return self._name -    def get_default(self): -        for key, val in self.get_enums(): -            if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) -        return self._default -    def get_stdint_type(self): -        if self.get_bit_width() <=  8: return 'uint8_t' -        if self.get_bit_width() <= 16: return 'uint16_t' -        if self.get_bit_width() <= 32: return 'uint32_t' -        if self.get_bit_width() <= 64: return 'uint64_t' -        raise Exception, 'too damn big' -    def get_shift(self): return self._addr_spec[0] -    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) -    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 -  if __name__ == '__main__':      regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) -    safe_makedirs(os.path.dirname(sys.argv[1]))      open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py index 6077b61b6..2ac73efcf 100644..100755 --- a/host/lib/ic_reg_maps/gen_ad9777_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py @@ -1,32 +1,23 @@  #!/usr/bin/env python  # -# Copyright 2008,2009 Free Software Foundation, Inc. -#  -# This file is part of GNU Radio -#  -# GNU Radio is free software; you can redistribute it and/or modify +# 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 asversion 3, or (at your option) -# any later version. -#  -# GNU Radio is distributed in the hope that it will be useful, +# 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 GNU Radio; see the file COPYING.  If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# -import re -import os  import sys -from Cheetah.Template import Template -def parse_tmpl(_tmpl_text, **kwargs): -    return str(Template(_tmpl_text, kwargs)) -def safe_makedirs(path): -    not os.path.isdir(path) and os.makedirs(path) +from common import *  ########################################################################  # Template for raw text data describing registers @@ -155,48 +146,6 @@ struct ad9777_regs_t{  \#endif /* INCLUDED_AD9777_REGS_HPP */  """ -class reg: -    def __init__(self, reg_des): -        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) -        name, addr, bit_range, default, enums = x.groups() - -        #store variables -        self._name = name -        self._addr = int(addr, 16) -        if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':'))) -        else: self._addr_spec = int(bit_range), int(bit_range) -        self._default = int(default, 16) - -        #extract enum -        self._enums = list() -        if enums: -            enum_val = 0 -            for enum_str in map(str.strip, enums.split(',')): -                if '=' in enum_str: -                    enum_name, enum_val = enum_str.split('=') -                    enum_val = int(enum_val) -                else: enum_name = enum_str -                self._enums.append((enum_name, enum_val)) -                enum_val += 1 - -    def get_addr(self): return self._addr -    def get_enums(self): return self._enums -    def get_name(self): return self._name -    def get_default(self): -        for key, val in self.get_enums(): -            if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) -        return self._default -    def get_stdint_type(self): -        if self.get_bit_width() <=  8: return 'uint8_t' -        if self.get_bit_width() <= 16: return 'uint16_t' -        if self.get_bit_width() <= 32: return 'uint32_t' -        if self.get_bit_width() <= 64: return 'uint64_t' -        raise Exception, 'too damn big' -    def get_shift(self): return self._addr_spec[0] -    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) -    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 -  if __name__ == '__main__':      regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) -    safe_makedirs(os.path.dirname(sys.argv[1]))      open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py index bcad1ffd3..478e471a3 100755 --- a/host/lib/ic_reg_maps/gen_adf4360_regs.py +++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py @@ -1,32 +1,23 @@  #!/usr/bin/env python  # -# Copyright 2008,2009 Free Software Foundation, Inc. -#  -# This file is part of GNU Radio -#  -# GNU Radio is free software; you can redistribute it and/or modify +# 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 asversion 3, or (at your option) -# any later version. -#  -# GNU Radio is distributed in the hope that it will be useful, +# 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 GNU Radio; see the file COPYING.  If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# -import re -import os  import sys -from Cheetah.Template import Template -def parse_tmpl(_tmpl_text, **kwargs): -    return str(Template(_tmpl_text, kwargs)) -def safe_makedirs(path): -    not os.path.isdir(path) and os.makedirs(path) +from common import *  ########################################################################  # Template for raw text data describing registers @@ -126,48 +117,6 @@ struct adf4360_regs_t{  \#endif /* INCLUDED_ADF4360_REGS_HPP */  """ -class reg: -    def __init__(self, reg_des): -        x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) -        name, addr, bit_range, default, enums = x.groups() - -        #store variables -        self._name = name -        self._addr = int(addr) -        if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':')) -        else: self._addr_spec = int(bit_range), int(bit_range) -        self._default = int(default) - -        #extract enum -        self._enums = list() -        if enums: -            enum_val = 0 -            for enum_str in map(str.strip, enums.split(',')): -                if '=' in enum_str: -                    enum_name, enum_val = enum_str.split('=') -                    enum_val = int(enum_val) -                else: enum_name = enum_str -                self._enums.append((enum_name, enum_val)) -                enum_val += 1 - -    def get_addr(self): return self._addr -    def get_enums(self): return self._enums -    def get_name(self): return self._name -    def get_default(self): -        for key, val in self.get_enums(): -            if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) -        return self._default -    def get_stdint_type(self): -        if self.get_bit_width() <=  8: return 'uint8_t' -        if self.get_bit_width() <= 16: return 'uint16_t' -        if self.get_bit_width() <= 32: return 'uint32_t' -        if self.get_bit_width() <= 64: return 'uint64_t' -        raise Exception, 'too damn big' -    def get_shift(self): return self._addr_spec[0] -    def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) -    def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 -  if __name__ == '__main__':      regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) -    safe_makedirs(os.path.dirname(sys.argv[1]))      open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/ic_reg_maps/gen_max2829_regs.py b/host/lib/ic_reg_maps/gen_max2829_regs.py new file mode 100755 index 000000000..7fef302a8 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_max2829_regs.py @@ -0,0 +1,166 @@ +#!/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/>. +# + +import sys +from common import * + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## +######################################################################## +## Standby (2) +######################################################################## +_set_to_1_2_0         2[0]          1 +_set_to_1_2_1         2[1]          1 +_set_to_1_2_2         2[2]          1 +pa_bias_dac           2[10]         0 +voltage_ref           2[11]         0 +_set_to_1_2_12        2[12]         1 +mimo_select           2[13]         0                 normal, mimo +######################################################################## +## Integer Divider Ratio (3) +######################################################################## +int_div_ratio_word    3[0:7]        a2 +frac_div_ratio_lsb    3[12:13]      0 +######################################################################## +## Fractional Divider Ratio (4) +######################################################################## +frac_div_ratio_msb    4[0:13]       0 +######################################################################## +## Band Select and PLL (5) +######################################################################## +band_select           5[0]          0                 2_4ghz, 5ghz +ref_divider           5[1:3]        1 +pll_cp_select         5[5]          1                 2ma, 4ma +band_select_802_11a   5[6]          0                 4_9ghz_to_5_35ghz, 5_47ghz_to_5_875ghz +vco_bandswitch        5[7]          0                 disable, automatic +vco_spi_bandswitch    5[8]          0                 fsm, spi +vco_sub_band          5[9:10]       0 +_set_to_1_5_11        5[11]         1 +_set_to_1_5_12        5[12]         1 +band_sel_mimo         5[13]         0                 normal, mimo +######################################################################## +## Calibration (6) +######################################################################## +rx_cal_mode           6[0]          0                 dis, enb +tx_cal_mode           6[1]          0                 dis, enb +_set_to_1_6_10        6[10]         1 +iq_cal_gain           6[11:12]      3                 8db, 18db, 24db, 34db +######################################################################## +## Lowpass Filter (7) +######################################################################## +rx_lpf_fine_adj       7[0:2]        2                 90, 95, 100, 105, 110 +rx_lpf_coarse_adj     7[3:4]        1                 7_5mhz, 9_5mhz, 14mhz, 18mhz +tx_lpf_coarse_adj     7[5:6]        1                 12mhz=1, 18mhz=2, 24mhz=3 +rssi_high_bw          7[11]         0                 2mhz, 6mhz +######################################################################## +## Rx Control/RSSI (8) +######################################################################## +_set_to_1_8_0         8[0]          1 +rx_highpass           8[2]          1                 100hz, 30khz +_set_to_1_8_5         8[5]          1 +rssi_pin_fcn          8[8]          0                 rssi, temp +rssi_op_mode          8[10]         0                 rssi_rxhp, enabled +rssi_output_range     8[11]         0                 low, high +rx_vga_gain_spi       8[12]         0                 io, spi +######################################################################## +## Tx Linearity/Baseband Gain (9) +######################################################################## +tx_baseband_gain      9[0:1]        0                 0db, 2db, 3_5db, 5db +tx_upconv_linearity   9[2:3]        0                 50, 63, 78, 100 +tx_vga_linearity      9[6:7]        0                 50, 63, 78, 100 +pa_driver_linearity   9[8:9]        2                 50, 63, 78, 100 +tx_vga_gain_spi       9[10]         0                 io, spi +######################################################################## +## PA Bias DAC (10) +######################################################################## +pa_bias_dac_out_curr  a[0:5]        0 +pa_bias_dac_delay     a[6:9]        f +######################################################################## +## Rx Gain (11) +######################################################################## +rx_vga_gain           b[0:4]        1f +rx_lna_gain           b[5:6]        3 +######################################################################## +## Tx VGA Gain (12) +######################################################################## +tx_vga_gain           c[0:5]        0 +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_MAX2829_REGS_HPP +\#define INCLUDED_MAX2829_REGS_HPP + +\#include <boost/cstdint.hpp> + +struct max2829_regs_t{ +#for $reg in $regs +    #if $reg.get_enums() +    enum $(reg.get_name())_t{ +        #for $i, $enum in enumerate($reg.get_enums()) +        #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' +        $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma +        #end for +    } $reg.get_name(); +    #else +    boost::$reg.get_stdint_type() $reg.get_name(); +    #end if +#end for + +    max2829_regs_t(void){ +#for $reg in $regs +        $reg.get_name() = $reg.get_default(); +#end for +    } + +    boost::uint32_t get_reg(boost::uint8_t addr){ +        boost::uint16_t reg = 0; +        switch(addr){ +        #for $addr in range(2, 12+1) +        case $addr: +            #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +            reg |= (boost::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +            #end for +            break; +        #end for +        } +        return (boost::uint32_t(reg) << 4) | (addr & 0xf); +    } +}; + +\#endif /* INCLUDED_MAX2829_REGS_HPP */ +""" + +if __name__ == '__main__': +    regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) +    open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp index 2a6854f50..8c3d6b17a 100644 --- a/host/lib/transport/convert_types.cpp +++ b/host/lib/transport/convert_types.cpp @@ -19,6 +19,7 @@  #include <uhd/utils/assert.hpp>  #include <boost/asio.hpp> //endianness conversion  #include <boost/cstdint.hpp> +#include <complex>  using namespace uhd; @@ -109,7 +110,7 @@ void transport::convert_io_type_to_otw_type(      size_t num_samps  ){      //all we handle for now: -    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); +    UHD_ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);      switch(io_type.tid){      case io_type_t::COMPLEX_FLOAT32: @@ -129,7 +130,7 @@ void transport::convert_otw_type_to_io_type(      size_t num_samps  ){      //all we handle for now: -    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); +    UHD_ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);      switch(io_type.tid){      case io_type_t::COMPLEX_FLOAT32: diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 0fd2522cf..14f7651d4 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -25,11 +25,14 @@  #include <uhd/types/mac_addr.hpp>  #include <uhd/types/otw_type.hpp>  #include <uhd/types/io_type.hpp> +#include <uhd/types/serial.hpp>  #include <boost/algorithm/string.hpp>  #include <boost/math/special_functions/round.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp>  #include <boost/cstdint.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/thread.hpp>  #include <stdexcept>  #include <complex> @@ -102,9 +105,9 @@ tx_metadata_t::tx_metadata_t(void){  /***********************************************************************   * time spec   **********************************************************************/ -time_spec_t::time_spec_t(boost::uint32_t new_secs, double new_nsecs){ -    secs = new_secs; -    nsecs = new_nsecs; +time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){ +    secs = secs_; +    nsecs = nsecs_;  }  boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ @@ -118,46 +121,44 @@ void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){  /***********************************************************************   * device addr   **********************************************************************/ -std::string device_addr_t::to_string(void) const{ -    std::stringstream ss; -    BOOST_FOREACH(std::string key, this->keys()){ -        ss << boost::format("%s: %s") % key % (*this)[key] << std::endl; -    } -    return ss.str(); -} - -static const std::string arg_delim = ";"; +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; -    BOOST_FOREACH(const std::string &key, this->keys()){ -        args_str += key + pair_delim + (*this)[key] + arg_delim; -    } -    return args_str; -} - -device_addr_t device_addr_t::from_args_str(const std::string &args_str){ -    device_addr_t addr; - +device_addr_t::device_addr_t(const std::string &args){      //split the args at the semi-colons      std::vector<std::string> pairs; -    boost::split(pairs, args_str, boost::is_any_of(arg_delim)); +    boost::split(pairs, args, 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]); +        if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); +        (*this)[trim(key_val[0])] = trim(key_val[1]);      } +} + +std::string device_addr_t::to_string(void) const{ +    if (this->size() == 0) return "Empty Device Address"; -    return addr; +    std::stringstream ss; +    BOOST_FOREACH(std::string key, this->keys()){ +        ss << boost::format("%s: %s") % key % (*this)[key] << std::endl; +    } +    return ss.str(); +} + +std::string device_addr_t::to_args_str(void) const{ +    std::string args_str; +    BOOST_FOREACH(const std::string &key, this->keys()){ +        args_str += key + pair_delim + (*this)[key] + arg_delim; +    } +    return args_str;  }  /*********************************************************************** @@ -243,3 +244,38 @@ io_type_t::io_type_t(size_t size)  : size(size), tid(CUSTOM_TYPE){      /* NOP */  } + +/*********************************************************************** + * serial + **********************************************************************/ +spi_config_t::spi_config_t(edge_t edge){ +    mosi_edge = edge; +    miso_edge = edge; +} + +void i2c_iface::write_eeprom( +    boost::uint8_t addr, +    boost::uint8_t offset, +    const byte_vector_t &bytes +){ +    for (size_t i = 0; i < bytes.size(); i++){ +        //write a byte at a time, its easy that way +        byte_vector_t cmd = boost::assign::list_of(offset+i)(bytes[i]); +        this->write_i2c(addr, cmd); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); //worst case write +    } +} + +byte_vector_t i2c_iface::read_eeprom( +    boost::uint8_t addr, +    boost::uint8_t offset, +    size_t num_bytes +){ +    byte_vector_t bytes; +    for (size_t i = 0; i < num_bytes; i++){ +        //do a zero byte write to start read cycle +        this->write_i2c(addr, byte_vector_t(1, offset+i)); +        bytes.push_back(this->read_i2c(addr, 1).at(0)); +    } +    return bytes; +} diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index aad2398d8..b0fbbd2ec 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -153,6 +153,12 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){      case SUBDEV_PROP_USE_LO_OFFSET:          val = false;          return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = true; //there is no LO, so it must be true! +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -164,19 +170,17 @@ 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<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<float>() == float(0));          return;      case SUBDEV_PROP_ANTENNA: -        ASSERT_THROW(val.as<std::string>() == std::string("")); +        UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));          return;      case SUBDEV_PROP_FREQ:          return; // it wont do you much good, but you can set it -    default: throw std::runtime_error(str(boost::format( -            "Error: trying to set read-only property on %s subdev" -        ) % dboard_id::to_string(get_rx_id()))); +    default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -248,6 +252,12 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){      case SUBDEV_PROP_USE_LO_OFFSET:          val = false;          return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = true; //there is no LO, so it must be true! +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -259,18 +269,16 @@ 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<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<float>() == float(0));          return;      case SUBDEV_PROP_ANTENNA: -        ASSERT_THROW(val.as<std::string>() == std::string("")); +        UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));          return;      case SUBDEV_PROP_FREQ:          return; // it wont do you much good, but you can set it -    default: throw std::runtime_error(str(boost::format( -            "Error: trying to set read-only property on %s subdev" -        ) % dboard_id::to_string(get_tx_id()))); +    default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index cd5b8447b..175f55eab 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -94,6 +94,15 @@ private:       * \return the actual frequency in Hz       */      double set_lo_freq(dboard_iface::unit_t unit, double target_freq); + +    /*! +     * Get the lock detect status of the LO. +     * \param unit which unit rx or tx +     * \return true for locked +     */ +    bool get_locked(dboard_iface::unit_t unit){ +        return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0; +    }  };  /*********************************************************************** @@ -192,7 +201,7 @@ void rfx_xcvr::set_tx_lo_freq(double freq){  void rfx_xcvr::set_rx_ant(const std::string &ant){      //validate input -    ASSERT_THROW(ant == "TX/RX" or ant == "RX2"); +    UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2");      //set the rx atr regs that change with antenna setting      this->get_iface()->set_atr_reg( @@ -350,12 +359,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        ASSERT_THROW(name == "PGA0"); +        UHD_ASSERT_THROW(name == "PGA0");          val = _rx_pga0_gain;          return;      case SUBDEV_PROP_GAIN_RANGE: -        ASSERT_THROW(name == "PGA0"); +        UHD_ASSERT_THROW(name == "PGA0");          val = gain_range_t(0, _max_rx_pga0_gain, float(0.022));          return; @@ -396,6 +405,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){      case SUBDEV_PROP_USE_LO_OFFSET:          val = false;          return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(dboard_iface::UNIT_RX); +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -411,7 +426,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        ASSERT_THROW(name == "PGA0"); +        UHD_ASSERT_THROW(name == "PGA0");          set_rx_pga0_gain(val.as<float>());          return; @@ -419,10 +434,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){          set_rx_ant(val.as<std::string>());          return; -    default: -        throw std::runtime_error(str(boost::format( -            "Error: trying to set read-only property on %s subdev" -        ) % dboard_id::to_string(get_rx_id()))); +    default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -430,7 +442,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){   * TX Get and Set   **********************************************************************/  void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ -        wax::obj key; std::string name; +    wax::obj key; std::string name;      boost::tie(key, name) = extract_named_prop(key_);      //handle the get request conditioned on the key @@ -486,6 +498,12 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){      case SUBDEV_PROP_USE_LO_OFFSET:          val = true;          return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(dboard_iface::UNIT_TX); +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -506,12 +524,9 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ANTENNA:          //its always set to tx/rx, so we only allow this value -        ASSERT_THROW(val.as<std::string>() == "TX/RX"); +        UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");          return; -    default: -        throw std::runtime_error(str(boost::format( -            "Error: trying to set read-only property on %s subdev" -        ) % dboard_id::to_string(get_tx_id()))); +    default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp new file mode 100644 index 000000000..0dfef2a0a --- /dev/null +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -0,0 +1,627 @@ +// +// 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/>. +// + +// TX IO Pins +#define HB_PA_OFF_TXIO      (1 << 15)    // 5GHz PA, 1 = off, 0 = on +#define LB_PA_OFF_TXIO      (1 << 14)    // 2.4GHz PA, 1 = off, 0 = on +#define ANTSEL_TX1_RX2_TXIO (1 << 13)    // 1 = Ant 1 to TX, Ant 2 to RX +#define ANTSEL_TX2_RX1_TXIO (1 << 12)    // 1 = Ant 2 to TX, Ant 1 to RX +#define TX_EN_TXIO          (1 << 11)    // 1 = TX on, 0 = TX off +#define AD9515DIV_TXIO      (1 << 4)     // 1 = Div  by 3, 0 = Div by 2 + +#define TXIO_MASK (HB_PA_OFF_TXIO | LB_PA_OFF_TXIO | ANTSEL_TX1_RX2_TXIO | ANTSEL_TX2_RX1_TXIO | TX_EN_TXIO | AD9515DIV_TXIO) + +// TX IO Functions +#define HB_PA_TXIO               LB_PA_OFF_TXIO +#define LB_PA_TXIO               HB_PA_OFF_TXIO +#define TX_ENB_TXIO              TX_EN_TXIO +#define TX_DIS_TXIO              0 +#define AD9515DIV_3_TXIO         AD9515DIV_TXIO +#define AD9515DIV_2_TXIO         0 + +// RX IO Pins +#define LOCKDET_RXIO (1 << 15)           // This is an INPUT!!! +#define POWER_RXIO   (1 << 14)           // 1 = power on, 0 = shutdown +#define RX_EN_RXIO   (1 << 13)           // 1 = RX on, 0 = RX off +#define RX_HP_RXIO   (1 << 12)           // 0 = Fc set by rx_hpf, 1 = 600 KHz + +#define RXIO_MASK (POWER_RXIO | RX_EN_RXIO | RX_HP_RXIO) + +// RX IO Functions +#define POWER_UP_RXIO            POWER_RXIO +#define POWER_DOWN_RXIO          0 +#define RX_ENB_RXIO              RX_EN_RXIO +#define RX_DIS_RXIO              0 + +#include "max2829_regs.hpp" +#include <uhd/utils/static.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <boost/math/special_functions/round.hpp> +#include <utility> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The XCVR 2450 constants + **********************************************************************/ +static const bool xcvr2450_debug = false; + +static const freq_range_t xcvr_freq_range(2.4e9, 6.0e9); + +static const prop_names_t xcvr_antennas = list_of("J1")("J2"); + +static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list_of +    ("VGA", gain_range_t(0, 30, 0.5)) +    ("BB", gain_range_t(0, 5, 1.5)) +; +static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of +    ("LNA", gain_range_t(0, 30.5, 15)) +    ("VGA", gain_range_t(0, 62, 2.0)) +; + +/*********************************************************************** + * The XCVR 2450 dboard class + **********************************************************************/ +class xcvr2450 : public xcvr_dboard_base{ +public: +    xcvr2450(ctor_args_t const& args); +    ~xcvr2450(void); + +    void rx_get(const wax::obj &key, wax::obj &val); +    void rx_set(const wax::obj &key, const wax::obj &val); + +    void tx_get(const wax::obj &key, wax::obj &val); +    void tx_set(const wax::obj &key, const wax::obj &val); + +private: +    double _lo_freq; +    uhd::dict<std::string, float> _tx_gains, _rx_gains; +    std::string _tx_ant, _rx_ant; +    int _ad9515div; +    max2829_regs_t _max2829_regs; + +    void set_lo_freq(double target_freq); +    void set_tx_ant(const std::string &ant); +    void set_rx_ant(const std::string &ant); +    void set_tx_gain(float gain, const std::string &name); +    void set_rx_gain(float gain, const std::string &name); + +    void update_atr(void); +    void spi_reset(void); +    void send_reg(boost::uint8_t addr){ +        boost::uint32_t value = _max2829_regs.get_reg(addr); +        if(xcvr2450_debug) std::cerr << boost::format( +            "XCVR2450: send reg 0x%02x, value 0x%05x" +        ) % int(addr) % value << std::endl; +        this->get_iface()->write_spi( +            dboard_iface::UNIT_RX, +            spi_config_t::EDGE_RISE, +            value, 24 +        ); +    } + +    static bool is_highband(double freq){return freq > 3e9;} + +    /*! +     * Is the LO locked? +     * \return true for locked +     */ +    bool get_locked(void){ +        return (this->get_iface()->read_gpio(dboard_iface::UNIT_RX) & LOCKDET_RXIO) != 0; +    } + +    /*! +     * Read the RSSI from the aux adc +     * \return the rssi in dB +     */ +    float get_rssi(void){ +        //constants for the rssi calculation +        static const float min_v = float(0.5), max_v = float(2.5); +        static const float rssi_dyn_range = 60; +        //calculate the rssi from the voltage +        float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, 1); +        return rssi_dyn_range*(voltage - min_v)/(max_v - min_v); +    } +}; + +/*********************************************************************** + * Register the XCVR 2450 dboard + **********************************************************************/ +static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t const& args){ +    return dboard_base::sptr(new xcvr2450(args)); +} + +UHD_STATIC_BLOCK(reg_xcvr2450_dboard){ +    //register the factory function for the rx and tx dbids +    dboard_manager::register_dboard(0x0060, &make_xcvr2450, "XCVR2450 TX"); +    dboard_manager::register_dboard(0x0061, &make_xcvr2450, "XCVR2450 RX"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +xcvr2450::xcvr2450(ctor_args_t const& args) : xcvr_dboard_base(args){ +    //enable only the clocks we need +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); + +    //set the gpio directions +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK); +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); + +    spi_reset(); //prepare the spi + +    //setup the misc max2829 registers +    _max2829_regs.mimo_select         = max2829_regs_t::MIMO_SELECT_MIMO; +    _max2829_regs.band_sel_mimo       = max2829_regs_t::BAND_SEL_MIMO_MIMO; +    _max2829_regs.pll_cp_select       = max2829_regs_t::PLL_CP_SELECT_4MA; +    _max2829_regs.rssi_high_bw        = max2829_regs_t::RSSI_HIGH_BW_6MHZ; +    _max2829_regs.tx_lpf_coarse_adj   = max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ; +    _max2829_regs.rx_lpf_coarse_adj   = max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ; +    _max2829_regs.rx_lpf_fine_adj     = max2829_regs_t::RX_LPF_FINE_ADJ_95; +    _max2829_regs.rx_vga_gain_spi     = max2829_regs_t::RX_VGA_GAIN_SPI_SPI; +    _max2829_regs.rssi_output_range   = max2829_regs_t::RSSI_OUTPUT_RANGE_HIGH; +    _max2829_regs.rssi_op_mode        = max2829_regs_t::RSSI_OP_MODE_ENABLED; +    _max2829_regs.rssi_pin_fcn        = max2829_regs_t::RSSI_PIN_FCN_RSSI; +    _max2829_regs.rx_highpass         = max2829_regs_t::RX_HIGHPASS_100HZ; +    _max2829_regs.tx_vga_gain_spi     = max2829_regs_t::TX_VGA_GAIN_SPI_SPI; +    _max2829_regs.pa_driver_linearity = max2829_regs_t::PA_DRIVER_LINEARITY_78; +    _max2829_regs.tx_vga_linearity    = max2829_regs_t::TX_VGA_LINEARITY_78; +    _max2829_regs.tx_upconv_linearity = max2829_regs_t::TX_UPCONV_LINEARITY_78; + +    //send initial register settings +    for(boost::uint8_t reg = 0x2; reg <= 0xC; reg++){ +        this->send_reg(reg); +    } + +    //set defaults for LO, gains, antennas +    set_lo_freq(2.45e9); +    set_rx_ant(xcvr_antennas.at(0)); +    set_tx_ant(xcvr_antennas.at(1)); +    BOOST_FOREACH(const std::string &name, xcvr_tx_gain_ranges.keys()){ +        set_tx_gain(xcvr_tx_gain_ranges[name].min, name); +    } +    BOOST_FOREACH(const std::string &name, xcvr_rx_gain_ranges.keys()){ +        set_rx_gain(xcvr_rx_gain_ranges[name].min, name); +    } +} + +xcvr2450::~xcvr2450(void){ +    spi_reset(); +} + +void xcvr2450::spi_reset(void){ +    //spi reset mode: global enable = off, tx and rx enable = on +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_ENB_TXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_ENB_RXIO | POWER_DOWN_RXIO); +    boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + +    //take it back out of spi reset mode and wait a bit +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_DIS_RXIO | POWER_UP_RXIO); +    boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +} + +void xcvr2450::update_atr(void){ +    //calculate tx atr pins +    int band_sel   = (xcvr2450::is_highband(_lo_freq))? HB_PA_TXIO : LB_PA_TXIO; +    int tx_ant_sel = (_tx_ant == "J1")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO; +    int rx_ant_sel = (_rx_ant == "J2")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO; +    int xx_ant_sel = tx_ant_sel; //prefer the tx antenna selection for full duplex (rx will get the other antenna) +    int ad9515div  = (_ad9515div == 3)? AD9515DIV_3_TXIO : AD9515DIV_2_TXIO; + +    //set the tx registers +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        band_sel | ad9515div | TX_DIS_TXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     band_sel | ad9515div | TX_DIS_TXIO | rx_ant_sel); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     band_sel | ad9515div | TX_ENB_TXIO | tx_ant_sel); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, band_sel | ad9515div | TX_ENB_TXIO | xx_ant_sel); + +    //set the rx registers +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        POWER_UP_RXIO | RX_DIS_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     POWER_UP_RXIO | RX_ENB_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     POWER_UP_RXIO | RX_DIS_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_ENB_RXIO); +} + +/*********************************************************************** + * Tuning + **********************************************************************/ +void xcvr2450::set_lo_freq(double target_freq){ +    target_freq = std::clip(target_freq, xcvr_freq_range.min, xcvr_freq_range.max); +    //TODO: clip for highband and lowband + +    //variables used in the calculation below +    double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0); +    double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_TX); +    int R, intdiv, fracdiv; + +    //loop through values until we get a match +    for(_ad9515div = 2; _ad9515div <= 3; _ad9515div++){ +        for(R = 1; R <= 7; R++){ +            double N = (target_freq*scaler*R*_ad9515div)/ref_freq; +            intdiv = int(std::floor(N)); +            fracdiv = boost::math::iround((N - intdiv)*double(1 << 16)); +            //actual minimum is 128, but most chips seems to require higher to lock +            if (intdiv < 131 or intdiv > 255) continue; +            //constraints met: exit loop +            goto done_loop; +        } +    } done_loop: + +    //calculate the actual freq from the values above +    double N = double(intdiv) + double(fracdiv)/double(1 << 16); +    _lo_freq = (N*ref_freq)/(scaler*R*_ad9515div); + +    if (xcvr2450_debug) std::cerr +        << boost::format("XCVR2450 tune:\n") +        << boost::format("    R=%d, N=%f, ad9515=%d, scaler=%f\n") % R % N % _ad9515div % scaler +        << boost::format("    Ref    Freq=%fMHz\n") % (ref_freq/1e6) +        << boost::format("    Target Freq=%fMHz\n") % (target_freq/1e6) +        << boost::format("    Actual Freq=%fMHz\n") % (_lo_freq/1e6) +        << std::endl; + +    //high-high band or low-high band? +    if(_lo_freq > (5.35e9 + 5.47e9)/2.0){ +        if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using  high-high band" << std::endl; +        _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_5_47GHZ_TO_5_875GHZ; +    }else{ +        if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using  low-high band" << std::endl; +        _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_4_9GHZ_TO_5_35GHZ; +    } + +    //new band select settings and ad9515 divider +    this->update_atr(); + +    //load new counters into registers +    _max2829_regs.int_div_ratio_word = intdiv; +    _max2829_regs.frac_div_ratio_lsb = fracdiv & 0x3; +    _max2829_regs.frac_div_ratio_msb = fracdiv >> 2; +    this->send_reg(0x3); //integer +    this->send_reg(0x4); //fractional + +    //load the reference divider and band select into registers +    //toggle the bandswitch from off to automatic (which really means start) +    _max2829_regs.ref_divider = R; +    _max2829_regs.band_select = (xcvr2450::is_highband(_lo_freq))? +                                max2829_regs_t::BAND_SELECT_5GHZ   : +                                max2829_regs_t::BAND_SELECT_2_4GHZ ; +    _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_DISABLE; +    this->send_reg(0x5); +    _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_AUTOMATIC;; +    this->send_reg(0x5); +} + +/*********************************************************************** + * Antenna Handling + **********************************************************************/ +void xcvr2450::set_tx_ant(const std::string &ant){ +    assert_has(xcvr_antennas, ant, "xcvr antenna name"); +   _tx_ant = ant; +    this->update_atr(); //sets the atr to the new antenna setting +} + +void xcvr2450::set_rx_ant(const std::string &ant){ +    assert_has(xcvr_antennas, ant, "xcvr antenna name"); +    _rx_ant = ant; +    this->update_atr(); //sets the atr to the new antenna setting +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/*! + * Convert a requested gain for the tx vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 6 bit the register value + */ +static int gain_to_tx_vga_reg(float &gain){ +    //calculate the register value +    int reg = std::clip(boost::math::iround(gain*60/30.0) + 3, 0, 63); + +    //calculate the actual gain value +    if (reg < 4)       gain = 0; +    else if (reg < 48) gain = float(reg/2 - 1); +    else               gain = float(reg/2.0 - 1.5); + +    //return register value +    return reg; +} + +/*! + * Convert a requested gain for the tx bb into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return gain enum value + */ +static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){ +    int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3); +    switch(reg){ +    case 0: +        gain = 0; +        return max2829_regs_t::TX_BASEBAND_GAIN_0DB; +    case 1: +        gain = 2; +        return max2829_regs_t::TX_BASEBAND_GAIN_2DB; +    case 2: +        gain = 3.5; +        return max2829_regs_t::TX_BASEBAND_GAIN_3_5DB; +    case 3: +        gain = 5; +        return max2829_regs_t::TX_BASEBAND_GAIN_5DB; +    } +    BOOST_THROW_EXCEPTION(std::runtime_error("should not get here")); +    return max2829_regs_t::TX_BASEBAND_GAIN_0DB; +} + +/*! + * Convert a requested gain for the rx vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 5 bit the register value + */ +static int gain_to_rx_vga_reg(float &gain){ +    int reg = std::clip(boost::math::iround(gain/2.0), 0, 31); +    gain = float(reg*2); +    return reg; +} + +/*! + * Convert a requested gain for the rx lna into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 2 bit the register value + */ +static int gain_to_rx_lna_reg(float &gain){ +    int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3); +    switch(reg){ +    case 0: +    case 1: gain = 0;    break; +    case 2: gain = 15;   break; +    case 3: gain = 30.5; break; +    } +    return reg; +} + +void xcvr2450::set_tx_gain(float gain, const std::string &name){ +    assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name"); +    if (name == "VGA"){ +        _max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain); +        send_reg(0xC); +    } +    else if(name == "BB"){ +        _max2829_regs.tx_baseband_gain = gain_to_tx_bb_reg(gain); +        send_reg(0x9); +    } +    else UHD_ASSERT_THROW(false); +    _tx_gains[name] = gain; +} + +void xcvr2450::set_rx_gain(float gain, const std::string &name){ +    assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name"); +    if (name == "VGA"){ +        _max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain); +        send_reg(0xB); +    } +    else if(name == "LNA"){ +        _max2829_regs.rx_lna_gain = gain_to_rx_lna_reg(gain); +        send_reg(0xB); +    } +    else UHD_ASSERT_THROW(false); +    _rx_gains[name] = gain; +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = dboard_id::to_string(get_rx_id()); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        assert_has(_rx_gains.keys(), name, "xcvr rx gain name"); +        val = _rx_gains[name]; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name"); +        val = xcvr_rx_gain_ranges[name]; +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(xcvr_rx_gain_ranges.keys()); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = xcvr_freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = _rx_ant; +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = xcvr_antennas; +        return; + +    case SUBDEV_PROP_QUADRATURE: +        val = true; +        return; + +    case SUBDEV_PROP_IQ_SWAPPED: +        val = false; +        return; + +    case SUBDEV_PROP_SPECTRUM_INVERTED: +        val = false; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(); +        return; + +    case SUBDEV_PROP_RSSI: +        val = this->get_rssi(); +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        this->set_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        this->set_rx_gain(val.as<float>(), name); +        return; + +    case SUBDEV_PROP_ANTENNA: +        this->set_rx_ant(val.as<std::string>()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    } +} + +/*********************************************************************** + * TX Get and Set + **********************************************************************/ +void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = dboard_id::to_string(get_tx_id()); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        assert_has(_tx_gains.keys(), name, "xcvr tx gain name"); +        val = _tx_gains[name]; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name"); +        val = xcvr_tx_gain_ranges[name]; +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(xcvr_tx_gain_ranges.keys()); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = xcvr_freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = _tx_ant; +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = xcvr_antennas; +        return; + +    case SUBDEV_PROP_QUADRATURE: +        val = true; +        return; + +    case SUBDEV_PROP_IQ_SWAPPED: +        val = true; +        return; + +    case SUBDEV_PROP_SPECTRUM_INVERTED: +        val = false; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(); +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        set_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        this->set_tx_gain(val.as<float>(), name); +        return; + +    case SUBDEV_PROP_ANTENNA: +        this->set_tx_ant(val.as<std::string>()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    } +} diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp new file mode 100644 index 000000000..54e7a4fd9 --- /dev/null +++ b/host/lib/usrp/dboard_eeprom.cpp @@ -0,0 +1,102 @@ +// +// 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/usrp/dboard_eeprom.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/format.hpp> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; + +static const bool _dboard_eeprom_debug = false; + +//////////////////////////////////////////////////////////////////////// +// format of daughterboard EEPROM +// 00: 0xDB code for ``I'm a daughterboard'' +// 01:   .. Daughterboard ID (LSB) +// 02:   .. Daughterboard ID (MSB) +// 03:   .. io bits  7-0 direction (bit set if it's an output from m'board) +// 04:   .. io bits 15-8 direction (bit set if it's an output from m'board) +// 05:   .. ADC0 DC offset correction (LSB) +// 06:   .. ADC0 DC offset correction (MSB) +// 07:   .. ADC1 DC offset correction (LSB) +// 08:   .. ADC1 DC offset correction (MSB) +//  ... +// 1f:   .. negative of the sum of bytes [0x00, 0x1e] + +#define DB_EEPROM_MAGIC         0x00 +#define DB_EEPROM_MAGIC_VALUE   0xDB +#define DB_EEPROM_ID_LSB        0x01 +#define DB_EEPROM_ID_MSB        0x02 +#define DB_EEPROM_OE_LSB        0x03 +#define DB_EEPROM_OE_MSB        0x04 +#define DB_EEPROM_OFFSET_0_LSB  0x05 // offset correction for ADC or DAC 0 +#define DB_EEPROM_OFFSET_0_MSB  0x06 +#define DB_EEPROM_OFFSET_1_LSB  0x07 // offset correction for ADC or DAC 1 +#define DB_EEPROM_OFFSET_1_MSB  0x08 +#define DB_EEPROM_CHKSUM        0x1f + +#define DB_EEPROM_CLEN          0x20 // length of common portion of eeprom + +#define DB_EEPROM_CUSTOM_BASE   DB_EEPROM_CLEN // first avail offset for +                                               //   daughterboard specific use +//////////////////////////////////////////////////////////////////////// + +//negative sum of bytes excluding checksum byte +static boost::uint8_t checksum(const byte_vector_t &bytes){ +    int sum = 0; +    for (size_t i = 0; i < std::min(bytes.size(), size_t(DB_EEPROM_CHKSUM)); i++){ +        sum -= int(bytes.at(i)); +    } +    if (_dboard_eeprom_debug) +        std::cout << boost::format("sum: 0x%02x") % sum << std::endl; +    return boost::uint8_t(sum); +} + +dboard_eeprom_t::dboard_eeprom_t(const byte_vector_t &bytes){ +    if (_dboard_eeprom_debug){ +        for (size_t i = 0; i < bytes.size(); i++){ +            std::cout << boost::format( +                "eeprom byte[0x%02x] = 0x%02x") % i % int(bytes.at(i) +            ) << std::endl; +        } +    } +    try{ +        UHD_ASSERT_THROW(bytes.size() >= DB_EEPROM_CLEN); +        UHD_ASSERT_THROW(bytes[DB_EEPROM_MAGIC] == DB_EEPROM_MAGIC_VALUE); +        UHD_ASSERT_THROW(bytes[DB_EEPROM_CHKSUM] == checksum(bytes)); +        id = \ +            (boost::uint16_t(bytes[DB_EEPROM_ID_LSB]) << 0) | +            (boost::uint16_t(bytes[DB_EEPROM_ID_MSB]) << 8) ; +    }catch(const uhd::assert_error &){ +        id = dboard_id::NONE; +    } +} + +byte_vector_t dboard_eeprom_t::get_eeprom_bytes(void){ +    byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros +    bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE; +    bytes[DB_EEPROM_ID_LSB] = boost::uint8_t(id >> 0); +    bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id >> 8); +    bytes[DB_EEPROM_CHKSUM] = checksum(bytes); +    return bytes; +} + +size_t dboard_eeprom_t::num_bytes(void){ +    return DB_EEPROM_CLEN; +} diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 06f8c55b6..390c1d3c9 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -177,10 +177,11 @@ static args_t get_dboard_args(      //verify that there is a registered constructor for this id      if (not get_id_to_args_map().has_key(dboard_id)){ -        throw std::runtime_error(str( +        /*throw std::runtime_error(str(              boost::format("Unregistered %s dboard id: %s")              % xx_type % dboard_id::to_string(dboard_id) -        )); +        ));*/ +        return get_dboard_args(dboard_id::NONE, xx_type);      }      //return the dboard args for this id @@ -205,7 +206,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); +        UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);          BOOST_FOREACH(const std::string &subdev, rx_subdevs){              dboard_base::sptr xcvr_dboard = rx_dboard_ctor(                  dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, tx_dboard_id) diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index 11ee3a798..a8c104485 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -42,14 +42,14 @@ public:          _tx_dsp = _mboard[MBOARD_PROP_TX_DSP];          //extract rx subdevice -        wax::obj rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD]; -        std::string rx_subdev_in_use = rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -        _rx_subdev = rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]; +        _rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD]; +        std::string rx_subdev_in_use = _rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); +        _rx_subdev = _rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)];          //extract tx subdevice -        wax::obj tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD]; -        std::string tx_subdev_in_use = tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -        _tx_subdev = tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]; +        _tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD]; +        std::string tx_subdev_in_use = _tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); +        _tx_subdev = _tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)];      }      ~simple_usrp_impl(void){ @@ -61,7 +61,26 @@ public:      }      std::string get_name(void){ -        return _mboard[MBOARD_PROP_NAME].as<std::string>(); +        return str(boost::format( +            "Simple USRP:\n" +            "  Device: %s\n" +            "  Mboard: %s\n" +            "  RX DSP: %s\n" +            "  RX Dboard: %s\n" +            "  RX Subdev: %s\n" +            "  TX DSP: %s\n" +            "  TX Dboard: %s\n" +            "  TX Subdev: %s\n" +        ) +            % (*_dev)[DEVICE_PROP_NAME].as<std::string>() +            % _mboard[MBOARD_PROP_NAME].as<std::string>() +            % _rx_dsp[DSP_PROP_NAME].as<std::string>() +            % _rx_dboard[DBOARD_PROP_NAME].as<std::string>() +            % _rx_subdev[SUBDEV_PROP_NAME].as<std::string>() +            % _tx_dsp[DSP_PROP_NAME].as<std::string>() +            % _tx_dboard[DBOARD_PROP_NAME].as<std::string>() +            % _tx_subdev[SUBDEV_PROP_NAME].as<std::string>() +        );      }      /******************************************************************* @@ -83,6 +102,10 @@ public:          _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;      } +    float read_rssi(void){ +        return _rx_subdev[SUBDEV_PROP_RSSI].as<float>(); +    } +      /*******************************************************************       * RX methods       ******************************************************************/ @@ -126,6 +149,10 @@ public:          return _rx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      } +    bool get_rx_lo_locked(void){ +        return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>(); +    } +      /*******************************************************************       * TX methods       ******************************************************************/ @@ -169,11 +196,17 @@ public:          return _tx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      } +    bool get_tx_lo_locked(void){ +        return _tx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>(); +    } +  private:      device::sptr _dev;      wax::obj _mboard;      wax::obj _rx_dsp;      wax::obj _tx_dsp; +    wax::obj _rx_dboard; +    wax::obj _tx_dboard;      wax::obj _rx_subdev;      wax::obj _tx_subdev;  }; @@ -181,6 +214,6 @@ private:  /***********************************************************************   * The Make Function   **********************************************************************/ -simple_usrp::sptr simple_usrp::make(const std::string &args){ -    return sptr(new simple_usrp_impl(device_addr_t::from_args_str(args))); +simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ +    return sptr(new simple_usrp_impl(dev_addr));  } diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp index dcd7ce9da..72f1f1c7a 100644 --- a/host/lib/usrp/usrp2/clock_control.cpp +++ b/host/lib/usrp/usrp2/clock_control.cpp @@ -21,6 +21,7 @@  #include "usrp2_regs.hpp" //spi slave constants  #include <boost/cstdint.hpp> +using namespace uhd;  using namespace uhd::usrp;  /*! diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 2859a7981..74d80163c 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -17,14 +17,17 @@  #include "usrp2_iface.hpp"  #include "clock_control.hpp" -#include "usrp2_regs.hpp" +#include "usrp2_regs.hpp" //wishbone address constants +#include <uhd/usrp/dboard_iface.hpp>  #include <uhd/types/dict.hpp>  #include <uhd/utils/assert.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/asio.hpp> //htonl and ntohl  #include <boost/math/special_functions/round.hpp> -#include <algorithm> +#include "ad7922_regs.hpp" //aux adc +#include "ad5624_regs.hpp" //aux dac +using namespace uhd;  using namespace uhd::usrp;  class usrp2_dboard_iface : public dboard_iface{ @@ -39,8 +42,8 @@ public:      void set_gpio_ddr(unit_t, boost::uint16_t);      boost::uint16_t read_gpio(unit_t); -    void write_i2c(int, const byte_vector_t &); -    byte_vector_t read_i2c(int, size_t); +    void write_i2c(boost::uint8_t, const byte_vector_t &); +    byte_vector_t read_i2c(boost::uint8_t, size_t);      double get_clock_rate(unit_t);      void set_clock_enabled(unit_t, bool); @@ -64,6 +67,9 @@ private:      usrp2_iface::sptr _iface;      clock_control::sptr _clk_ctrl;      boost::uint32_t _ddr_shadow; + +    uhd::dict<unit_t, ad5624_regs_t> _dac_regs; +    void _write_aux_dac(unit_t);  };  /*********************************************************************** @@ -91,6 +97,16 @@ usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::s      }      _iface->poke32(FR_GPIO_TX_SEL, new_sels);      _iface->poke32(FR_GPIO_RX_SEL, new_sels); + +    //reset the aux dacs +    _dac_regs[UNIT_RX] = ad5624_regs_t(); +    _dac_regs[UNIT_TX] = ad5624_regs_t(); +    BOOST_FOREACH(unit_t unit, _dac_regs.keys()){ +        _dac_regs[unit].data = 1; +        _dac_regs[unit].addr = ad5624_regs_t::ADDR_ALL; +        _dac_regs[unit].cmd  = ad5624_regs_t::CMD_RESET; +        this->_write_aux_dac(unit); +    }  }  usrp2_dboard_iface::~usrp2_dboard_iface(void){ @@ -196,84 +212,67 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(  /***********************************************************************   * I2C   **********************************************************************/ -void usrp2_dboard_iface::write_i2c(int i2c_addr, const byte_vector_t &buf){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO); -    out_data.data.i2c_args.addr = i2c_addr; -    out_data.data.i2c_args.bytes = buf.size(); - -    //limitation of i2c transaction size -    ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data)); - -    //copy in the data -    std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data); - -    //send and recv -    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); +void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ +    return _iface->write_i2c(addr, bytes);  } -dboard_iface::byte_vector_t usrp2_dboard_iface::read_i2c(int i2c_addr, size_t num_bytes){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO); -    out_data.data.i2c_args.addr = i2c_addr; -    out_data.data.i2c_args.bytes = num_bytes; - -    //limitation of i2c transaction size -    ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data)); - -    //send and recv -    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); -    ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); - -    //copy out the data -    byte_vector_t result(num_bytes); -    std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin()); -    return result; +byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ +    return _iface->read_i2c(addr, num_bytes);  }  /***********************************************************************   * Aux DAX/ADC   **********************************************************************/ -/*! - * Static function to convert a unit type enum - * to an over-the-wire value for the usrp2 control. - * \param unit the dboard interface unit type enum - * \return an over the wire representation - */ -static boost::uint8_t unit_to_otw(dboard_iface::unit_t unit){ -    switch(unit){ -    case dboard_iface::UNIT_TX: return USRP2_DIR_TX; -    case dboard_iface::UNIT_RX: return USRP2_DIR_RX; -    } -    throw std::invalid_argument("unknown unit type"); +void usrp2_dboard_iface::_write_aux_dac(unit_t unit){ +    static const uhd::dict<unit_t, int> unit_to_spi_dac = boost::assign::map_list_of +        (UNIT_RX, SPI_SS_RX_DAC) +        (UNIT_TX, SPI_SS_TX_DAC) +    ; +    _iface->transact_spi( +        unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,  +        _dac_regs[unit].get_reg(), 24, false /*no rb*/ +    );  }  void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); -    out_data.data.aux_args.dir = unit_to_otw(unit); -    out_data.data.aux_args.which = which; -    out_data.data.aux_args.value = htonl(boost::math::iround(4095*value/3.3)); - -    //send and recv -    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE); +    _dac_regs[unit].data = boost::math::iround(4095*value/3.3); +    _dac_regs[unit].cmd = ad5624_regs_t::CMD_WR_UP_DAC_CHAN_N; +    switch(which){ +    case 0: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_A; break; +    case 1: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_B; break; +    case 2: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_C; break; +    case 3: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_D; break; +    default: throw std::runtime_error("not a possible aux dac, must be 0, 1, 2, or 3"); +    } +    this->_write_aux_dac(unit);  }  float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){ -    //setup the out data -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO); -    out_data.data.aux_args.dir = unit_to_otw(unit); -    out_data.data.aux_args.which = which; - -    //send and recv -    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE); -    return float(3.3*ntohl(in_data.data.aux_args.value)/4095); +    static const uhd::dict<unit_t, int> unit_to_spi_adc = boost::assign::map_list_of +        (UNIT_RX, SPI_SS_RX_ADC) +        (UNIT_TX, SPI_SS_TX_ADC) +    ; + +    //setup spi config args +    spi_config_t config; +    config.mosi_edge = spi_config_t::EDGE_FALL; +    config.miso_edge = spi_config_t::EDGE_RISE; + +    //setup the spi registers +    ad7922_regs_t ad7922_regs; +    ad7922_regs.mod = which; //normal mode: mod == chn +    ad7922_regs.chn = which; + +    //write and read spi +    _iface->transact_spi( +        unit_to_spi_adc[unit], config, +        ad7922_regs.get_reg(), 16, false /*no rb*/ +    ); +    ad7922_regs.set_reg(boost::uint16_t(_iface->transact_spi( +        unit_to_spi_adc[unit], config, +        ad7922_regs.get_reg(), 16, true /*rb*/ +    ))); + +    //convert to voltage and return +    return float(3.3*ad7922_regs.result/4095);  } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index fe74219d6..403faf5cf 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -33,22 +33,16 @@ using namespace uhd::usrp;   * Helper Methods   **********************************************************************/  void usrp2_impl::dboard_init(void){ -    //grab the dboard ids over the control line -    usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO); -    usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE); - -    //extract the dboard ids an convert them -    dboard_id_t rx_dboard_id = ntohs(in_data.data.dboard_ids.rx_id); -    dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id); +    //read the dboard eeprom to extract the dboard ids +    _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); +    _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));      //create a new dboard interface and manager      dboard_iface::sptr _dboard_iface(          make_usrp2_dboard_iface(_iface, _clk_ctrl)      );      _dboard_manager = dboard_manager::make( -        rx_dboard_id, tx_dboard_id, _dboard_iface +        _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface      );      //load dboards @@ -72,7 +66,7 @@ void usrp2_impl::dboard_init(void){  void usrp2_impl::update_rx_mux_config(void){      //calculate the rx mux      boost::uint32_t rx_mux = 0; -    ASSERT_THROW(_rx_subdevs_in_use.size() == 1); +    UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1);      wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0));      std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;      if (rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>()){ @@ -90,11 +84,11 @@ void usrp2_impl::update_rx_mux_config(void){  void usrp2_impl::update_tx_mux_config(void){      //calculate the tx mux      boost::uint32_t tx_mux = 0x10; -    ASSERT_THROW(_tx_subdevs_in_use.size() == 1); +    UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1);      wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0));      std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;      if (tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){ -        tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0); +        tx_mux = (((tx_mux >> 0) & 0xf) << 4) | (((tx_mux >> 4) & 0xf) << 0);      }      _iface->poke32(FR_DSP_TX_MUX, tx_mux); @@ -125,19 +119,28 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _rx_subdevs_in_use;          return; -    //case DBOARD_PROP_CODEC: -    //    throw std::runtime_error("unhandled prop in usrp2 dboard"); +    case DBOARD_PROP_DBOARD_ID: +        val = _rx_db_eeprom.id; +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  }  void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ -    if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){ +    switch(key.as<dboard_prop_t>()){ +    case DBOARD_PROP_USED_SUBDEVS:          _rx_subdevs_in_use = val.as<prop_names_t>();          update_rx_mux_config(); //if the val is bad, this will throw          return; -    } -    throw std::runtime_error("Cannot set on usrp2 dboard"); +    case DBOARD_PROP_DBOARD_ID: +        _rx_db_eeprom.id = val.as<dboard_id_t>(); +        _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    }  }  /*********************************************************************** @@ -165,17 +168,26 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _tx_subdevs_in_use;          return; -    //case DBOARD_PROP_CODEC: -    //    throw std::runtime_error("unhandled prop in usrp2 dboard"); +    case DBOARD_PROP_DBOARD_ID: +        val = _tx_db_eeprom.id; +        return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  }  void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ -    if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){ +    switch(key.as<dboard_prop_t>()){ +    case DBOARD_PROP_USED_SUBDEVS:          _tx_subdevs_in_use = val.as<prop_names_t>();          update_tx_mux_config(); //if the val is bad, this will throw          return; -    } -    throw std::runtime_error("Cannot set on usrp2 dboard"); +    case DBOARD_PROP_DBOARD_ID: +        _tx_db_eeprom.id = val.as<dboard_id_t>(); +        _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    }  } diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 204277ba7..84314a656 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -40,7 +40,7 @@ template <class T> T log2(T num){   * DDC Helper Methods   **********************************************************************/  static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){ -    ASSERT_THROW(std::abs(freq) < clock_freq/2.0); +    UHD_ASSERT_THROW(std::abs(freq) < clock_freq/2.0);      static const double scale_factor = std::pow(2.0, 32);      //calculate the freq register word @@ -117,6 +117,8 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){      case DSP_PROP_HOST_RATE:          val = get_master_clock_freq()/_ddc_decim;          return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -139,8 +141,7 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){          }          return; -    default: -        throw std::runtime_error("Error: trying to set read-only property on usrp2 ddc0"); +    default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -200,6 +201,8 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){      case DSP_PROP_HOST_RATE:          val = get_master_clock_freq()/_duc_interp;          return; + +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -222,7 +225,6 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){          }          return; -    default: -        throw std::runtime_error("Error: trying to set read-only property on usrp2 duc0"); +    default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index b600a2a70..e80001ff2 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -32,6 +32,10 @@ extern "C" {  #define _SINS_  #endif +//defines the protocol version in this shared header +//increment this value when the protocol is changed +#define USRP2_PROTO_VERSION 2 +  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 @@ -57,9 +61,6 @@ typedef enum{      USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE = 'M',      USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO = 'n', -    USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO = 'd', -    USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE = 'D', -      USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's',      USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S', @@ -69,12 +70,6 @@ typedef enum{      USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',      USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H', -    USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO = 'x', -    USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE = 'X', - -    USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO = 'y', -    USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE = 'Y', -      USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO = '{',      USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE = '}', @@ -89,26 +84,23 @@ typedef enum{  } usrp2_ctrl_id_t;  typedef enum{ -    USRP2_DIR_RX, -    USRP2_DIR_TX +    USRP2_DIR_RX = 'r', +    USRP2_DIR_TX = 't'  } usrp2_dir_which_t;  typedef enum{ -    USRP2_CLK_EDGE_RISE, -    USRP2_CLK_EDGE_FALL +    USRP2_CLK_EDGE_RISE = 'r', +    USRP2_CLK_EDGE_FALL = 'f'  } usrp2_clk_edge_t;  typedef struct{ +    _SINS_ uint32_t proto_ver;      _SINS_ uint32_t id;      _SINS_ uint32_t seq;      union{          _SINS_ uint32_t ip_addr;          _SINS_ uint8_t mac_addr[6];          struct { -            _SINS_ uint16_t rx_id; -            _SINS_ uint16_t tx_id; -        } dboard_ids; -        struct {              _SINS_ uint8_t dev;              _SINS_ uint8_t miso_edge;              _SINS_ uint8_t mosi_edge; @@ -122,12 +114,6 @@ typedef struct{              _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];          } i2c_args;          struct { -            _SINS_ uint8_t dir; -            _SINS_ uint8_t which; -            _SINS_ uint8_t _pad[2]; -            _SINS_ uint32_t value; -        } aux_args; -        struct {              _SINS_ uint8_t now; //stream now?              _SINS_ uint8_t continuous; //auto-reload commmands?              _SINS_ uint8_t chain; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index d7728238c..36bef4f25 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -100,6 +100,7 @@ void usrp2_impl::update_clock_config(void){      case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break;      case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break;      case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break; +    default: throw std::runtime_error("usrp2: unhandled clock configuration reference source");      }      //clock source ref 10mhz @@ -151,7 +152,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      //send and recv      usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE); +    UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);  }  /*********************************************************************** @@ -170,7 +171,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){              //send and recv              usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -            ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); +            UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);              //extract the address              val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string(); @@ -184,7 +185,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){              //send and recv              usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -            ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); +            UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);              //extract the address              val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string(); @@ -208,7 +209,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_RX_DBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _rx_dboard_proxy->get_link();          return; @@ -217,7 +218,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_TX_DBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _tx_dboard_proxy->get_link();          return; @@ -226,7 +227,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_RX_DSP: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _rx_dsp_proxy->get_link();          return; @@ -235,7 +236,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_TX_DSP: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _tx_dsp_proxy->get_link();          return; @@ -247,9 +248,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          val = _clock_config;          return; -    default: -        throw std::runtime_error("Error: trying to get write-only property on usrp2 mboard"); - +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -268,7 +267,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){              //send and recv              usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -            ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); +            UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);              return;          } @@ -280,7 +279,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){              //send and recv              usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); -            ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); +            UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);              return;          }      } @@ -305,8 +304,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){          issue_ddc_stream_cmd(val.as<stream_cmd_t>());          return; -    default: -        throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard"); - +    default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 5c84fd8d3..e43b9678e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -19,12 +19,13 @@  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp>  #include <boost/thread.hpp> +#include <boost/foreach.hpp>  #include <boost/asio.hpp> //used for htonl and ntohl  #include <boost/assign/list_of.hpp>  #include <stdexcept> +#include <algorithm>  using namespace uhd; -using namespace uhd::usrp;  class usrp2_iface_impl : public usrp2_iface{  public: @@ -85,9 +86,51 @@ public:          //send and recv          usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); -        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); +        UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); -        return ntohl(out_data.data.spi_args.data); +        return ntohl(in_data.data.spi_args.data); +    } + +/*********************************************************************** + * I2C + **********************************************************************/ +    void write_i2c(boost::uint8_t addr, const byte_vector_t &buf){ +        //setup the out data +        usrp2_ctrl_data_t out_data; +        out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO); +        out_data.data.i2c_args.addr = addr; +        out_data.data.i2c_args.bytes = buf.size(); + +        //limitation of i2c transaction size +        UHD_ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data)); + +        //copy in the data +        std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data); + +        //send and recv +        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); +        UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); +    } + +    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ +        //setup the out data +        usrp2_ctrl_data_t out_data; +        out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO); +        out_data.data.i2c_args.addr = addr; +        out_data.data.i2c_args.bytes = num_bytes; + +        //limitation of i2c transaction size +        UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data)); + +        //send and recv +        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); +        UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); +        UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); + +        //copy out the data +        byte_vector_t result(num_bytes); +        std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin()); +        return result;      }  /*********************************************************************** @@ -98,6 +141,7 @@ public:          //fill in the seq number and send          usrp2_ctrl_data_t out_copy = out_data; +        out_copy.proto_ver = htonl(USRP2_PROTO_VERSION);          out_copy.seq = htonl(++_ctrl_seq_num);          _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); @@ -105,6 +149,13 @@ public:          while(true){              usrp2_ctrl_data_t in_data;              size_t len = _ctrl_transport->recv(boost::asio::buffer(&in_data, sizeof(in_data))); +            if(len >= sizeof(boost::uint32_t) and ntohl(in_data.proto_ver) != USRP2_PROTO_VERSION){ +                throw std::runtime_error(str( +                    boost::format("Expected protocol version %d, but got %d\n" +                    "The firmware build does not match the host code build." +                    ) % int(USRP2_PROTO_VERSION) % ntohl(in_data.proto_ver) +                )); +            }              if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){                  return in_data;              } @@ -142,7 +193,7 @@ private:          //send and recv          usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); -        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); +        UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);      }      template <class T> T peek(boost::uint32_t addr){ @@ -154,7 +205,7 @@ private:          //send and recv          usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); -        ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); +        UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);          return T(ntohl(out_data.data.poke_args.data));      } diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 1298d87f1..7158c58d0 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -19,18 +19,27 @@  #define INCLUDED_USRP2_IFACE_HPP  #include <uhd/transport/udp_simple.hpp> -#include <uhd/usrp/dboard_iface.hpp> //spi config +#include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include <boost/cstdint.hpp>  #include "fw_common.h" +//////////////////////////////////////////////////////////////////////// +// I2C addresses +//////////////////////////////////////////////////////////////////////// +#define I2C_DEV_EEPROM  0x50 // 24LC02[45]:  7-bits 1010xxx +#define	I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) +#define	I2C_ADDR_TX_DB  (I2C_DEV_EEPROM | 0x4) +#define	I2C_ADDR_RX_DB  (I2C_DEV_EEPROM | 0x5) +//////////////////////////////////////////////////////////////////////// +  /*!   * The usrp2 interface class:   * Provides a set of functions to implementation layer.   * Including spi, peek, poke, control...   */ -class usrp2_iface : boost::noncopyable{ +class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{  public:      typedef boost::shared_ptr<usrp2_iface> sptr; @@ -87,7 +96,7 @@ public:       */      virtual boost::uint32_t transact_spi(          int which_slave, -        const uhd::usrp::spi_config_t &config, +        const uhd::spi_config_t &config,          boost::uint32_t data,          size_t num_bits,          bool readback diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 3bdc5bd02..4079357f9 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -70,6 +70,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){      //send a hello control packet      usrp2_ctrl_data_t ctrl_data_out; +    ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);      ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);      udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); @@ -185,7 +186,7 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){          return;      case DEVICE_PROP_MBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _mboard_proxy->get_link();          return; @@ -201,9 +202,10 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){          val = size_t(_max_tx_samples_per_packet);          return; +    default: UHD_THROW_PROP_GET_ERROR();      }  }  void usrp2_impl::set(const wax::obj &, const wax::obj &){ -    throw std::runtime_error("Cannot set in usrp2 device"); +    UHD_THROW_PROP_SET_ERROR();  } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index dbcee367b..1c9387744 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -25,6 +25,7 @@  #include <uhd/types/otw_type.hpp>  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/clock_config.hpp> +#include <uhd/usrp/dboard_eeprom.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp>  #include <uhd/transport/vrt.hpp> @@ -161,12 +162,14 @@ private:      void rx_dboard_set(const wax::obj &, const wax::obj &);      wax_obj_proxy::sptr _rx_dboard_proxy;      uhd::prop_names_t _rx_subdevs_in_use; +    uhd::usrp::dboard_eeprom_t _rx_db_eeprom;      //properties interface for tx dboard      void tx_dboard_get(const wax::obj &, wax::obj &);      void tx_dboard_set(const wax::obj &, const wax::obj &);      wax_obj_proxy::sptr _tx_dboard_proxy;      uhd::prop_names_t _tx_subdevs_in_use; +    uhd::usrp::dboard_eeprom_t _tx_db_eeprom;      void update_rx_mux_config(void);      void update_tx_mux_config(void); diff --git a/host/lib/usrp/usrp_e/dboard_iface.cpp b/host/lib/usrp/usrp_e/dboard_iface.cpp index 12e8fe206..f69cdd2b4 100644 --- a/host/lib/usrp/usrp_e/dboard_iface.cpp +++ b/host/lib/usrp/usrp_e/dboard_iface.cpp @@ -23,6 +23,7 @@  #include <boost/assign/list_of.hpp>  #include <linux/usrp_e.h> //i2c and spi constants +using namespace uhd;  using namespace uhd::usrp;  class usrp_e_dboard_iface : public dboard_iface{ @@ -37,8 +38,8 @@ public:      void set_gpio_ddr(unit_t, boost::uint16_t);      boost::uint16_t read_gpio(unit_t); -    void write_i2c(int, const byte_vector_t &); -    byte_vector_t read_i2c(int, size_t); +    void write_i2c(boost::uint8_t, const byte_vector_t &); +    byte_vector_t read_i2c(boost::uint8_t, size_t);      void write_spi(          unit_t unit, @@ -169,41 +170,12 @@ boost::uint32_t usrp_e_dboard_iface::read_write_spi(  /***********************************************************************   * I2C   **********************************************************************/ -static const size_t max_i2c_data_bytes = 10; - -void usrp_e_dboard_iface::write_i2c(int i2c_addr, const byte_vector_t &buf){ -    //allocate some memory for this transaction -    ASSERT_THROW(buf.size() <= max_i2c_data_bytes); -    boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - -    //load the data struct -    usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem); -    data.addr = i2c_addr; -    data.len = buf.size(); -    std::copy(buf.begin(), buf.end(), data.data); - -    //call the spi ioctl -    _iface->ioctl(USRP_E_I2C_WRITE, &data); +void usrp_e_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ +    return _iface->write_i2c(addr, bytes);  } -dboard_iface::byte_vector_t usrp_e_dboard_iface::read_i2c(int i2c_addr, size_t num_bytes){ -    //allocate some memory for this transaction -    ASSERT_THROW(num_bytes <= max_i2c_data_bytes); -    boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - -    //load the data struct -    usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem); -    data.addr = i2c_addr; -    data.len = num_bytes; - -    //call the spi ioctl -    _iface->ioctl(USRP_E_I2C_READ, &data); - -    //unload the data -    byte_vector_t ret(data.len); -    ASSERT_THROW(ret.size() == num_bytes); -    std::copy(data.data, data.data+ret.size(), ret.begin()); -    return ret; +byte_vector_t usrp_e_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ +    return _iface->read_i2c(addr, num_bytes);  }  /*********************************************************************** diff --git a/host/lib/usrp/usrp_e/dboard_impl.cpp b/host/lib/usrp/usrp_e/dboard_impl.cpp index df0f1d9a9..e87a2c0a5 100644 --- a/host/lib/usrp/usrp_e/dboard_impl.cpp +++ b/host/lib/usrp/usrp_e/dboard_impl.cpp @@ -50,26 +50,26 @@ void usrp_e_impl::dboard_init(void){   * RX Dboard Get   **********************************************************************/  void usrp_e_impl::rx_dboard_get(const wax::obj &, wax::obj &){ -     +    UHD_THROW_PROP_GET_ERROR();  }  /***********************************************************************   * RX Dboard Set   **********************************************************************/  void usrp_e_impl::rx_dboard_set(const wax::obj &, const wax::obj &){ -     +    UHD_THROW_PROP_SET_ERROR();  }  /***********************************************************************   * TX Dboard Get   **********************************************************************/  void usrp_e_impl::tx_dboard_get(const wax::obj &, wax::obj &){ -     +    UHD_THROW_PROP_GET_ERROR();  }  /***********************************************************************   * TX Dboard Set   **********************************************************************/  void usrp_e_impl::tx_dboard_set(const wax::obj &, const wax::obj &){ -     +    UHD_THROW_PROP_SET_ERROR();  } diff --git a/host/lib/usrp/usrp_e/dsp_impl.cpp b/host/lib/usrp/usrp_e/dsp_impl.cpp index e32c76a3d..272ac71b3 100644 --- a/host/lib/usrp/usrp_e/dsp_impl.cpp +++ b/host/lib/usrp/usrp_e/dsp_impl.cpp @@ -34,14 +34,14 @@ void usrp_e_impl::rx_ddc_init(void){   * RX DDC Get   **********************************************************************/  void usrp_e_impl::rx_ddc_get(const wax::obj &, wax::obj &){ -     +    UHD_THROW_PROP_GET_ERROR();  }  /***********************************************************************   * RX DDC Set   **********************************************************************/  void usrp_e_impl::rx_ddc_set(const wax::obj &, const wax::obj &){ -     +    UHD_THROW_PROP_SET_ERROR();  }  /*********************************************************************** @@ -58,12 +58,12 @@ void usrp_e_impl::tx_duc_init(void){   * TX DUC Get   **********************************************************************/  void usrp_e_impl::tx_duc_get(const wax::obj &, wax::obj &){ -     +    UHD_THROW_PROP_GET_ERROR();  }  /***********************************************************************   * TX DUC Set   **********************************************************************/  void usrp_e_impl::tx_duc_set(const wax::obj &, const wax::obj &){ -     +    UHD_THROW_PROP_SET_ERROR();  } diff --git a/host/lib/usrp/usrp_e/mboard_impl.cpp b/host/lib/usrp/usrp_e/mboard_impl.cpp index 2d225c6ea..00ce4b782 100644 --- a/host/lib/usrp/usrp_e/mboard_impl.cpp +++ b/host/lib/usrp/usrp_e/mboard_impl.cpp @@ -58,7 +58,7 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_RX_DBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _rx_dboard_proxy->get_link();          return; @@ -67,7 +67,7 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_TX_DBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _tx_dboard_proxy->get_link();          return; @@ -80,7 +80,7 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_RX_DSP: -        ASSERT_THROW(name == "ddc0"); +        UHD_ASSERT_THROW(name == "ddc0");          val = _rx_ddc_proxy->get_link();          return; @@ -89,7 +89,7 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_TX_DSP: -        ASSERT_THROW(name == "duc0"); +        UHD_ASSERT_THROW(name == "duc0");          val = _tx_duc_proxy->get_link();          return; @@ -101,10 +101,7 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){          val = _clock_config;          return; -    case MBOARD_PROP_TIME_NOW: -    case MBOARD_PROP_TIME_NEXT_PPS: -        throw std::runtime_error("Error: trying to get write-only property on usrp-e mboard"); - +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -112,5 +109,5 @@ void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){   * Mboard Set   **********************************************************************/  void usrp_e_impl::mboard_set(const wax::obj &, const wax::obj &){ -     +    UHD_THROW_PROP_SET_ERROR();  } diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.cpp b/host/lib/usrp/usrp_e/usrp_e_iface.cpp index d4c988211..41737a716 100644 --- a/host/lib/usrp/usrp_e/usrp_e_iface.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_iface.cpp @@ -16,11 +16,14 @@  //  #include "usrp_e_iface.hpp" +#include <uhd/utils/assert.hpp>  #include <sys/ioctl.h> //ioctl  #include <linux/usrp_e.h> //ioctl structures and constants  #include <boost/format.hpp>  #include <stdexcept> +using namespace uhd; +  class usrp_e_iface_impl : public usrp_e_iface{  public: @@ -96,11 +99,51 @@ public:      }      /******************************************************************* +     * I2C +     ******************************************************************/ +    static const size_t max_i2c_data_bytes = 10; + +    void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ +        //allocate some memory for this transaction +        UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes); +        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; + +        //load the data struct +        usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem); +        data.addr = addr; +        data.len = bytes.size(); +        std::copy(bytes.begin(), bytes.end(), data.data); + +        //call the spi ioctl +        this->ioctl(USRP_E_I2C_WRITE, &data); +    } + +    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ +        //allocate some memory for this transaction +        UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes); +        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; + +        //load the data struct +        usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem); +        data.addr = addr; +        data.len = num_bytes; + +        //call the spi ioctl +        this->ioctl(USRP_E_I2C_READ, &data); + +        //unload the data +        byte_vector_t bytes(data.len); +        UHD_ASSERT_THROW(bytes.size() == num_bytes); +        std::copy(data.data, data.data+bytes.size(), bytes.begin()); +        return bytes; +    } + +    /*******************************************************************       * SPI       ******************************************************************/      boost::uint32_t transact_spi(          int which_slave, -        const uhd::usrp::spi_config_t &config, +        const spi_config_t &config,          boost::uint32_t bits,          size_t num_bits,          bool readback @@ -114,8 +157,8 @@ public:          //load the flags          data.flags = 0; -        data.flags |= (config.miso_edge == uhd::usrp::spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; -        data.flags |= (config.mosi_edge == uhd::usrp::spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL  : UE_SPI_PUSH_RISE; +        data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; +        data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL  : UE_SPI_PUSH_RISE;          //call the spi ioctl          this->ioctl(USRP_E_SPI, &data); diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.hpp b/host/lib/usrp/usrp_e/usrp_e_iface.hpp index 4fc3bb33d..763d19581 100644 --- a/host/lib/usrp/usrp_e/usrp_e_iface.hpp +++ b/host/lib/usrp/usrp_e/usrp_e_iface.hpp @@ -19,7 +19,7 @@  #define INCLUDED_USRP_E_IFACE_HPP  #include <uhd/transport/udp_simple.hpp> -#include <uhd/usrp/dboard_iface.hpp> //spi config +#include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include <boost/cstdint.hpp> @@ -29,7 +29,7 @@   * Provides a set of functions to implementation layer.   * Including spi, peek, poke, control...   */ -class usrp_e_iface : boost::noncopyable{ +class usrp_e_iface : boost::noncopyable, public uhd::i2c_iface{  public:      typedef boost::shared_ptr<usrp_e_iface> sptr; @@ -87,7 +87,7 @@ public:       */      virtual boost::uint32_t transact_spi(          int which_slave, -        const uhd::usrp::spi_config_t &config, +        const uhd::spi_config_t &config,          boost::uint32_t data,          size_t num_bits,          bool readback diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.cpp b/host/lib/usrp/usrp_e/usrp_e_impl.cpp index 4d08210e2..211b939ee 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.cpp @@ -112,7 +112,7 @@ void usrp_e_impl::get(const wax::obj &key_, wax::obj &val){          return;      case DEVICE_PROP_MBOARD: -        ASSERT_THROW(name == ""); +        UHD_ASSERT_THROW(name == "");          val = _mboard_proxy->get_link();          return; @@ -128,6 +128,7 @@ void usrp_e_impl::get(const wax::obj &key_, wax::obj &val){          val = size_t(_max_num_samples);          return; +    default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -135,7 +136,7 @@ void usrp_e_impl::get(const wax::obj &key_, wax::obj &val){   * Device Set   **********************************************************************/  void usrp_e_impl::set(const wax::obj &, const wax::obj &){ -    throw std::runtime_error("Cannot set in usrp-e device"); +    UHD_THROW_PROP_SET_ERROR();  }  /*********************************************************************** diff --git a/host/lib/utils.cpp b/host/lib/utils.cpp new file mode 100644 index 000000000..3a1e5aa3f --- /dev/null +++ b/host/lib/utils.cpp @@ -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/>. +// + +#include <uhd/utils/props.hpp> + +using namespace uhd; + +/*********************************************************************** + * Props + **********************************************************************/ +named_prop_t::named_prop_t( +    const wax::obj &key_, +    const std::string &name_ +){ +    key = key_; +    name = name_; +} + +typedef boost::tuple<wax::obj, std::string> named_prop_tuple; + +named_prop_tuple uhd::extract_named_prop( +    const wax::obj &key, +    const std::string &name +){ +    if (key.type() == typeid(named_prop_t)){ +        named_prop_t np = key.as<named_prop_t>(); +        return named_prop_tuple(np.key, np.name); +    } +    return named_prop_tuple(key, name); +} diff --git a/host/test/addr_test.cpp b/host/test/addr_test.cpp index 2ec6de14b..93b7cc0df 100644 --- a/host/test/addr_test.cpp +++ b/host/test/addr_test.cpp @@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_device_addr){      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); +    uhd::device_addr_t new_dev_addr(args_str);      //they should be the same size      BOOST_CHECK_EQUAL(dev_addr.size(), new_dev_addr.size()); diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index bf2ec5db7..5a9f2b714 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -72,6 +72,8 @@ private:          case PROP_GAIN_NAMES:              val = _gain_values.keys();              return; + +        default: UHD_THROW_PROP_GET_ERROR();          }      } @@ -87,9 +89,7 @@ private:              _gain_values[name] = val.as<float>();              return; -        case PROP_GAIN_RANGE: -        case PROP_GAIN_NAMES: -            throw std::runtime_error("cannot set this property"); +        default: UHD_THROW_PROP_SET_ERROR();          }      } diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 0b1e058ef..78970ad0e 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -27,4 +27,8 @@ ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp)  TARGET_LINK_LIBRARIES(usrp2_burner uhd)  INSTALL(TARGETS usrp2_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) +ADD_EXECUTABLE(uhd_burn_db_eeprom uhd_burn_db_eeprom.cpp) +TARGET_LINK_LIBRARIES(uhd_burn_db_eeprom uhd) +INSTALL(TARGETS uhd_burn_db_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) +  INSTALL(PROGRAMS usrp2_recovery.py DESTINATION ${PKG_DATA_DIR}/utils) diff --git a/host/utils/uhd_burn_db_eeprom.cpp b/host/utils/uhd_burn_db_eeprom.cpp new file mode 100644 index 000000000..c07b43f16 --- /dev/null +++ b/host/utils/uhd_burn_db_eeprom.cpp @@ -0,0 +1,105 @@ +// +// 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/device.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/usrp/dboard_id.hpp> +#include <uhd/usrp/device_props.hpp> +#include <uhd/usrp/mboard_props.hpp> +#include <uhd/usrp/dboard_props.hpp> +#include <boost/program_options.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/format.hpp> +#include <boost/assign.hpp> +#include <iostream> +#include <sstream> + +using namespace uhd; +using namespace uhd::usrp; +namespace po = boost::program_options; + +//used with lexical cast to parse a hex string +template <class T> struct to_hex{ +    T value; +    operator T() const {return value;} +    friend std::istream& operator>>(std::istream& in, to_hex& out){ +        in >> std::hex >> out.value; +        return in; +    } +}; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    //command line variables +    std::string args, db_name, unit; +    static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of +        ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) +    ; + +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "help message") +        ("args", po::value<std::string>(&args)->default_value(""),    "device address args [default = \"\"]") +        ("db",   po::value<std::string>(&db_name)->default_value(""), "dboard name [default = \"\"]") +        ("unit", po::value<std::string>(&unit)->default_value(""),    "which unit [RX or TX]") +        ("id",   po::value<std::string>(),                            "dboard id to burn (hex string), omit for readback") +    ; + +    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 Burn DB EEPROM %s") % desc << std::endl; +        std::cout << boost::format( +            "Omit the id argument to perform readback,\n" +            "Or specify a new id to burn into the eeprom.\n" +        ) << std::endl; +        return ~0; +    } + +    //check inputs +    if (not unit_to_db_prop.has_key(unit)){ +        std::cout << "Error: specify RX or TX for unit" << std::endl; +        return ~0; +    } + +    //make the device and extract the dboard w/ property +    device::sptr dev = device::make(args); +    wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], db_name)]; +    std::string prefix = (db_name == "")? unit : (unit + ":" + db_name); + +    //read the current dboard id from eeprom +    if (vm.count("id") == 0){ +        std::cout << boost::format("Getting dbid on %s dboard...") % prefix << std::endl; +        dboard_id_t id = dboard[DBOARD_PROP_DBOARD_ID].as<dboard_id_t>(); +        std::cout << boost::format("  Current dbid: %s") % dboard_id::to_string(id) << std::endl; +    } + +    //write a new dboard id to eeprom +    else{ +        dboard_id_t id = boost::lexical_cast<to_hex<dboard_id_t> >(vm["id"].as<std::string>()); +        std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl; +        std::cout << boost::format("  New dbid: %s") % dboard_id::to_string(id) << std::endl; +        dboard[DBOARD_PROP_DBOARD_ID] = id; +    } + +    std::cout << "  Done" << std::endl << std::endl; +    return 0; +} diff --git a/host/utils/uhd_find_devices.cpp b/host/utils/uhd_find_devices.cpp index 6c945cbca..8222dc1f4 100644 --- a/host/utils/uhd_find_devices.cpp +++ b/host/utils/uhd_find_devices.cpp @@ -27,8 +27,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      po::options_description desc("Allowed options");      desc.add_options()          ("help", "help message") -        ("addr", po::value<std::string>(), "resolvable network address") -        ("node", po::value<std::string>(), "path to linux device node") +        ("args", po::value<std::string>()->default_value(""), "device address args")      ;      po::variables_map vm; @@ -41,17 +40,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          return ~0;      } -    //load the options into the address -    uhd::device_addr_t device_addr; -    if (vm.count("addr")){ -        device_addr["addr"] = vm["addr"].as<std::string>(); -    } -    if (vm.count("node")){ -        device_addr["node"] = vm["node"].as<std::string>(); -    } -      //discover the usrps and print the results -    uhd::device_addrs_t device_addrs = uhd::device::find(device_addr); +    uhd::device_addrs_t device_addrs = uhd::device::find(vm["args"].as<std::string>());      if (device_addrs.size() == 0){          std::cerr << "No UHD Devices Found" << std::endl;  | 
