diff options
46 files changed, 1028 insertions, 530 deletions
diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 9cf4c163f..1c6e0624f 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -172,6 +172,33 @@ void handle_udp_data_packet( #define OTW_GPIO_BANK_TO_NUM(bank) \ (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) +//setup the output data +static usrp2_ctrl_data_t ctrl_data_out; +static struct socket_address i2c_src; +static struct socket_address spi_src; + +static volatile bool i2c_done = false; +void i2c_read_done_callback(void) { + //printf("I2C read done callback\n"); + i2c_async_data_ready(ctrl_data_out.data.i2c_args.data); + i2c_done = true; + i2c_register_callback(0); +} + +void i2c_write_done_callback(void) { + //printf("I2C write done callback\n"); + i2c_done = true; + i2c_register_callback(0); +} + +static volatile bool spi_done = false; +static volatile uint32_t spi_readback_data; +void get_spi_readback_data(void) { + ctrl_data_out.data.spi_args.data = spi_get_data(); + spi_done = true; + spi_register_callback(0); +} + void handle_udp_ctrl_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len @@ -197,11 +224,9 @@ void handle_udp_ctrl_packet( } //setup the output data - usrp2_ctrl_data_t ctrl_data_out = { - .proto_ver = USRP2_FW_COMPAT_NUM, - .id=USRP2_CTRL_ID_HUH_WHAT, - .seq=ctrl_data_in->seq - }; + ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM; + ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT; + ctrl_data_out.seq=ctrl_data_in->seq; //handle the data based on the id switch(ctrl_data_in_id){ @@ -212,6 +237,7 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_WAZZUP_BRO: ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; /******************************************************************* @@ -219,19 +245,21 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ //transact - uint32_t result = spi_transact( - (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, + bool success = spi_async_transact( + //(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, ctrl_data_in->data.spi_args.dev, //which device ctrl_data_in->data.spi_args.data, //32 bit data ctrl_data_in->data.spi_args.num_bits, //length in bits - (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | - (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL + (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | //flags + (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL, + get_spi_readback_data //callback ); //load output - ctrl_data_out.data.spi_args.data = result; ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; + spi_src = src; } +// send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; /******************************************************************* @@ -239,11 +267,13 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_read( + i2c_register_callback(i2c_read_done_callback); + i2c_async_read( ctrl_data_in->data.i2c_args.addr, - ctrl_data_out.data.i2c_args.data, num_bytes ); + i2c_src = src; +// i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } @@ -251,11 +281,14 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; - i2c_write( + i2c_register_callback(i2c_read_done_callback); + i2c_async_write( ctrl_data_in->data.i2c_args.addr, ctrl_data_in->data.i2c_args.data, num_bytes ); + i2c_src = src; +// i2c_dst = dst; ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; ctrl_data_out.data.i2c_args.bytes = num_bytes; } @@ -287,6 +320,7 @@ void handle_udp_ctrl_packet( } ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: @@ -309,6 +343,7 @@ void handle_udp_ctrl_packet( } ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); break; case USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO:{ @@ -335,9 +370,9 @@ void handle_udp_ctrl_packet( default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; - + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); } - send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + } /* @@ -503,6 +538,17 @@ main(void) buffer_irq_handler(0); + if(i2c_done) { + i2c_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, i2c_src, &ctrl_data_out, sizeof(ctrl_data_out)); + //printf("Sending UDP packet from main loop for I2C...\n"); + } + + if(spi_done) { + spi_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, spi_src, &ctrl_data_out, sizeof(ctrl_data_out)); + } + int pending = pic_regs->pending; // poll for under or overrun if (pending & PIC_UNDERRUN_INT){ diff --git a/firmware/microblaze/lib/dbsm.c b/firmware/microblaze/lib/dbsm.c index d495860fd..cee343eaa 100644 --- a/firmware/microblaze/lib/dbsm.c +++ b/firmware/microblaze/lib/dbsm.c @@ -160,12 +160,12 @@ dbsm_process_status(dbsm_t *sm, uint32_t status) putchar('E'); // Most likely an ethernet Rx error. We just restart the transfer. if (status & (BPS_ERROR(sm->buf0))) - //dbsm_error_helper(sm, sm->buf0); - dbsm_process_helper(sm, sm->buf0); //forward errors + dbsm_error_helper(sm, sm->buf0); + //dbsm_process_helper(sm, sm->buf0); //forward errors if (status & (BPS_ERROR(sm->buf0 ^ 1))) - //dbsm_error_helper(sm, sm->buf0 ^ 1); - dbsm_process_helper(sm, sm->buf0 ^ 1); //forward errors + dbsm_error_helper(sm, sm->buf0 ^ 1); + //dbsm_process_helper(sm, sm->buf0 ^ 1); //forward errors } if (status & BPS_DONE(sm->buf0)) diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c index 3f738733b..177341267 100644 --- a/firmware/microblaze/lib/i2c.c +++ b/firmware/microblaze/lib/i2c.c @@ -19,12 +19,15 @@ #include "i2c.h" #include "memory_map.h" #include "stdint.h" +#include <string.h> +#include "pic.h" +#include "nonstdio.h" #define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK) // prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally] -#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1) +#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 400000)) - 1) static uint16_t prescaler_values[MAX_WB_DIV+1] = { 0xffff, // 0: can't happen @@ -34,6 +37,18 @@ static uint16_t prescaler_values[MAX_WB_DIV+1] = { PRESCALER(4), // 4: 25 MHz }; +//asynchronous (interrupt-driven) i2c state variables +volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer +volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t i2c_len = 0; //length remaining in current transfer +volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state +i2c_dir_t i2c_dir; //I2C transfer direction + +void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete + +static void i2c_irq_handler(unsigned irq); +inline void i2c_async_err(void); + void i2c_init(void) { @@ -47,9 +62,10 @@ i2c_init(void) i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff; i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff; - i2c_regs->ctrl = I2C_CTRL_EN; // enable core + i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE; // enable core - // FIXME interrupt driven? + // FIXME interrupt driven? + pic_register_handler(IRQ_I2C, i2c_irq_handler); } static inline void @@ -107,7 +123,7 @@ i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0) // generate START and write addr (and maybe STOP) - i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); if (!wait_chk_ack()) goto fail; @@ -124,4 +140,163 @@ i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) return false; } - +static void i2c_irq_handler(unsigned irq) { +//i2c state machine. + + //printf("I2C irq handler\n"); + //first let's make sure nothing is f'ed up + //TODO: uncomment this error checking when we have some way to handle errors +// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it +// printf("\tNACK received\n"); +// i2c_async_err(); +// return; +// }// else printf("\tACK received, proceeding\n"); + + if(i2c_regs->cmd_status & I2C_ST_AL) { + printf("\tArbitration lost!\n"); + i2c_async_err(); + return; + } + + if(i2c_regs->cmd_status & I2C_ST_TIP) { + //printf("\tI2C still busy in interrupt\n"); + return; + } + + //now decide what to do + switch(i2c_state) { + + case I2C_STATE_IDLE: + //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. + printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); + i2c_async_err(); + break; + + case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. + case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg + + //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); + //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); + + if(i2c_dir == I2C_DIR_READ) { + if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + //set up another data byte + if(i2c_len > 1) //only one more byte to transfer + i2c_regs->cmd_status = I2C_CMD_RD; + else + i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; + } + else if(i2c_dir == I2C_DIR_WRITE) { + //write a byte + //printf("\tWriting %x\n", *i2c_bufptr); + i2c_regs->data = *(i2c_bufptr++); + if(i2c_len > 1) + i2c_regs->cmd_status = I2C_CMD_WR; + else { + //printf("\tGenerating STOP\n"); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; + } + }; + i2c_len--; + if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; + else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition + break; + + + case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. + //printf("\tI2C in state LAST BYTE\n"); + + if(i2c_dir == I2C_DIR_READ) { + *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + i2c_state = I2C_STATE_DATA_READY; + } else { + i2c_state = I2C_STATE_IDLE; + } + i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time + + if(i2c_callback) { + i2c_callback(); //if we registered a callback, call it! + } + + break; + + + default: //terrible things have happened. + break; + } + +} + +void i2c_register_callback(void (*volatile callback)(void)) { + i2c_callback = callback; +} + +inline void i2c_async_err(void) { + i2c_state = I2C_STATE_IDLE; + i2c_regs->ctrl &= ~I2C_CTRL_IE; + printf("I2C error\n"); +//TODO: set an error flag instead of just dropping things on the floor + i2c_regs->cmd_status = I2C_CMD_STOP; +} + +bool i2c_async_read(uint8_t addr, unsigned int len) { + //printf("Starting async read\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len == 0) return true; //just idiot-proofing + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + i2c_len = len; + i2c_dir = I2C_DIR_READ; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + return true; +} + +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { + //printf("Starting async write\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + //copy the buffer into our own if writing + memcpy((void *)i2c_buf, buf, len); + + i2c_len = len; + i2c_dir = I2C_DIR_WRITE; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + + return true; +} + +//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. +bool i2c_async_data_ready(void *buf) { + if(i2c_state == I2C_STATE_DATA_READY) { + i2c_state = I2C_STATE_IDLE; + memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this + //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); + return true; + } + return false; +} + + diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h index ecb6aa0d2..77129e922 100644 --- a/firmware/microblaze/lib/i2c.h +++ b/firmware/microblaze/lib/i2c.h @@ -20,20 +20,38 @@ #define INCLUDED_I2C_H #include <stdbool.h> +#include "stdint.h" + +typedef enum { I2C_STATE_IDLE, + I2C_STATE_CONTROL_BYTE_SENT, + I2C_STATE_DATA, + I2C_STATE_LAST_BYTE, + I2C_STATE_DATA_READY, + I2C_STATE_ERROR + } i2c_state_t; + +typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; void i2c_init(void); bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len); bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len); +bool i2c_async_read(uint8_t addr, unsigned int len); +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); +bool i2c_async_data_ready(void *); +//static void i2c_irq_handler(unsigned irq); +void i2c_register_callback(void (*callback)(void)); // Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. // Which EEPROM is determined by i2c_addr. See i2c_addr.h bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len); +bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); // Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. // Which EEPROM is determined by i2c_addr. See i2c_addr.h bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len); +bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); #endif /* INCLUDED_I2C_H */ diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c index bef808e57..2a41a1bfa 100644 --- a/firmware/microblaze/lib/spi.c +++ b/firmware/microblaze/lib/spi.c @@ -17,6 +17,12 @@ #include "spi.h" #include "memory_map.h" +#include "pic.h" +#include "nonstdio.h" + +void (*volatile spi_callback)(void); //SPI callback when xfer complete. + +static void spi_irq_handler(unsigned irq); void spi_init(void) @@ -59,3 +65,44 @@ spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags else return 0; } + +void spi_register_callback(void (*volatile callback)(void)) { + spi_callback = callback; +} + +static void spi_irq_handler(unsigned irq) { +// printf("SPI IRQ handler\n"); +// uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt + //spi_regs->ctrl &= ~SPI_CTRL_IE; + if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later +} + +uint32_t spi_get_data(void) { + return spi_regs->txrx0; +} + +bool +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { + flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); + int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + + if(spi_regs->ctrl & SPI_CTRL_GO_BSY) { + printf("Async SPI busy!\n"); + return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes. + } + + // Tell it which SPI slave device to access + spi_regs->ss = slave & 0xffff; + + // Data we will send + spi_regs->txrx0 = data; + + spi_register_callback(callback); + pic_register_handler(IRQ_SPI, spi_irq_handler); + + // Run it -- write once and rewrite with GO set + spi_regs->ctrl = ctrl; + spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + + return true; +} diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index 01e4d26fd..54618cedd 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,6 +48,13 @@ void spi_wait(void); uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); +uint32_t spi_get_data(void); +//static void spi_irq_handler(unsigned irq); +void spi_register_callback(void (*volatile callback)(void)); + +bool +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); + // ---------------------------------------------------------------- // Routines that manipulate the FLASH SPI BUS // ---------------------------------------------------------------- diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 75bc40859..8d666b76b 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -45,22 +45,26 @@ get_hw_rev(void) bool u2_init(void) { + hal_disable_ints(); hal_io_init(); // init spi, so that we can switch over to the high-speed clock spi_init(); - // init i2c so we can read our rev - i2c_init(); - get_hw_rev(); - // set up the default clocks clocks_init(); + hal_uart_init(); + + // init i2c so we can read our rev pic_init(); // progammable interrupt controller + i2c_init(); + hal_enable_ints(); + get_hw_rev(); + bp_init(); // buffer pool - hal_enable_ints(); + // flash all leds to let us know board is alive hal_set_leds(0x0, 0x1f); diff --git a/fpga/usrp2/vrt/vita_rx_framer.v b/fpga/usrp2/vrt/vita_rx_framer.v index fd82263d0..235817941 100644 --- a/fpga/usrp2/vrt/vita_rx_framer.v +++ b/fpga/usrp2/vrt/vita_rx_framer.v @@ -128,7 +128,7 @@ module vita_rx_framer VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; - VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b11,28'd0,flags_fifo_o}; + VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b10,28'd0,flags_fifo_o}; //VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer}; default : pkt_fifo_line <= 34'h0_FFFF_FFFF; diff --git a/host/config/Version.cmake b/host/config/Version.cmake index a592a4565..9e4b6b306 100644 --- a/host/config/Version.cmake +++ b/host/config/Version.cmake @@ -42,7 +42,7 @@ ELSE(${GIT} STREQUAL "GIT-NOTFOUND") #extract the timestamp from the git log entry EXECUTE_PROCESS( WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', '''${_git_log}''', re.MULTILINE | re.DOTALL).groups()[0]" + COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', ''' ${_git_log} ''', re.MULTILINE | re.DOTALL).groups()[0]" OUTPUT_VARIABLE _git_timestamp OUTPUT_STRIP_TRAILING_WHITESPACE ) diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index d0041f71c..b4383f88d 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -24,6 +24,7 @@ SET(manual_sources coding.rst dboards.rst general.rst + images.rst usrp2.rst ) diff --git a/host/docs/images.rst b/host/docs/images.rst new file mode 100644 index 000000000..ff5c5404e --- /dev/null +++ b/host/docs/images.rst @@ -0,0 +1,104 @@ +======================================================================== +UHD - Firmware and FPGA Image Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Images Overview +------------------------------------------------------------------------ +Every USRP device must be loaded with special firmware and FPGA images. +The methods of loading images into the device varies among devices: + +* **USRP1:** The host code will automatically load the firmware and FPGA at runtime. +* **USRP2:** The user must manually write the images onto the USRP2 SD card. + +------------------------------------------------------------------------ +Pre-built images +------------------------------------------------------------------------ + +Pre-built images are available for download. +See the UHD wiki for the download link. + +The pre-built images come in platform-specific installer packages +and platform-independent archive files: + +* **Linux:** DEB or RPM installer +* **Windows:** not available yet... +* **Macintosh:** not available yet... +* **Platform-independent:** ZIP or TAR.GZ archive + +^^^^^^^^^^^^^^^^^^ +Linux installers +^^^^^^^^^^^^^^^^^^ +The Linux-based installers will install the images into /usr/share/uhd/images. +On a Linux system, the UHD will always search this path for image files. + +Commands to install a linux rpm or deb package: + +:: + + sudo rpm -i <linux-images-installer>.rpm + + -- OR -- + + sudo dpkg -i <linux-images-installer>.deb + +^^^^^^^^^^^^^^^^^^^^^^ +Archive install +^^^^^^^^^^^^^^^^^^^^^^ +When installing images from an archive, there are two options: + +**Option 1:** + +Unpack the archive into the UHD installation prefix. +The UHD will always search <prefix>/share/uhd/images for image files. +Where <prefix> was set by the CMAKE_INSTALL_PREFIX at configure-time. + +**Option 2:** + +Unpack the archive anywhere and set the UHD_IMAGE_PATH environment variable. +The UHD_IMAGE_PATH may contain a list of directories to search for image files, +or paths to specific image files. + +------------------------------------------------------------------------ +Building images +------------------------------------------------------------------------ + +The UHD source repository comes with the source code necessary to build +both firmware and FPGA images for all supported devices. +The build commands for a particular image can be found in <uhd-repo-path>/images/Makefile. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Xilinx FPGA builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Xilinx ISE 12.x and up is required to build the Xilinx FPGA 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. + +See <uhd-repo-path>/fpga/usrp2/top/* + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Microblaze firmware builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Microblaze GCC compiler from the Xilinx EDK is required to build the Microblaze firmware images. +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. + +See <uhd-repo-path>/firmware/microblaze + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Altera FPGA builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Quartus is required to build the Altera FPGA images. +Pre-built images can also be found in <uhd-repo-path>/fpga/usrp1/rbf + +See <uhd-repo-path>/fpga/usrp1/toplevel/* + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +FX2 firmware builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The sdcc compiler is required to build the FX2 firmware images. +The build requires that you have a unix-like environment with autotools and make. + +See <uhd-repo-path>/firmware/fx2 diff --git a/host/docs/index.rst b/host/docs/index.rst index b31a3d0ac..6973ede19 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -21,6 +21,7 @@ Building the UHD Application Notes ^^^^^^^^^^^^^^^^^^^^^ * `General App Notes <./general.html>`_ +* `Firmware and FPGA Image Notes <./images.html>`_ * `USRP2 App Notes <./usrp2.html>`_ * `Daughterboard App Notes <./dboards.html>`_ diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index bc4ea0e44..3ac326f58 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -5,42 +5,6 @@ UHD - USRP2 Application Notes .. contents:: Table of Contents ------------------------------------------------------------------------ -Building firmware and FPGA images ------------------------------------------------------------------------- - -^^^^^^^^^^^^^^^^^^ -FPGA Image -^^^^^^^^^^^^^^^^^^ -Xilinx ISE 10.1 and up is required to build the FPGA image for the USRP2. -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 -f Makefile.udp 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 ./usrp2/usrp2_txrx_uhd.bin* - ------------------------------------------------------------------------- Load the images onto the SD card ------------------------------------------------------------------------ **Warning!** diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 76ee24e5f..130956f8a 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -33,6 +33,8 @@ INSTALL(FILES dboard_manager.hpp ### utilities ### + dsp_utils.hpp + misc_utils.hpp subdev_spec.hpp tune_helper.hpp diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index fc7ea3052..e776ecc42 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -65,11 +65,34 @@ public: AUX_ADC_B = 'b' }; + //! Special properties that differentiate this daughterboard slot + struct special_props_t{ + /*! + * Soft clock divider: + * When a motherboard cannot provided a divided dboard clock, + * it may provided a "soft" divided clock over an FPGA GPIO. + * The implementation must know the type of clock provided. + */ + bool soft_clock_divider; + + /*! + * Mangle i2c addresses: + * When i2c is shared across multiple daugterboard slots, + * the i2c addresses will be mangled on the secondary slot + * to avoid conflicts between slots in the i2c address space. + * The mangling is daguhterboard specific so the implementation + * needs to know whether it should use mangled addresses or not. + */ + bool mangle_i2c_addrs; + }; + /*! - * Get the motherboard name of the form: usrp1, usrp2... - * \return string representing the motherboard name + * Get special properties information for this dboard slot. + * This call helps the dboard code to handle implementation + * differences between different motherboards and dboard slots. + * \return the special properties struct */ - virtual std::string get_mboard_name(void) = 0; + virtual special_props_t get_special_props(void) = 0; /*! * Write to an aux dac. diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index e5831d4cf..c68f069f0 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -51,7 +51,7 @@ public: const dboard_id_t &dboard_id, dboard_ctor_t dboard_ctor, const std::string &name, - const prop_names_t &subdev_names = prop_names_t(1, "") + const prop_names_t &subdev_names = prop_names_t(1, "0") ); /*! diff --git a/host/include/uhd/usrp/dsp_utils.hpp b/host/include/uhd/usrp/dsp_utils.hpp new file mode 100644 index 000000000..8ec04dd2f --- /dev/null +++ b/host/include/uhd/usrp/dsp_utils.hpp @@ -0,0 +1,99 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_USRP_DSP_UTILS_HPP +#define INCLUDED_UHD_USRP_DSP_UTILS_HPP + +#include <uhd/config.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <boost/cstdint.hpp> + +namespace uhd{ namespace usrp{ + +namespace dsp_type1{ + + /*! + * Calculate the rx mux word from properties. + * \param subdev_conn the subdev connection type + * \return the 32-bit rx mux control word + */ + UHD_API boost::uint32_t calc_rx_mux_word(subdev_conn_t subdev_conn); + + /*! + * Calculate the tx mux word from properties. + * \param subdev_conn the subdev connection type + * \return the 32-bit tx mux control word + */ + UHD_API boost::uint32_t calc_tx_mux_word(subdev_conn_t subdev_conn); + + /*! + * Calculate the cordic word from the frequency and clock rate. + * The frequency will be set to the actual (possible) frequency. + * + * \param freq the requested frequency in Hz + * \param codec_rate the dsp codec rate in Hz + * \return the 32-bit cordic control word + */ + UHD_API boost::uint32_t calc_cordic_word_and_update( + double &freq, double codec_rate + ); + + /*! + * Calculate the CIC filter word from the rate. + * Check if requested decim/interp rate is: + * multiple of 4, enable two halfband filters + * multiple of 2, enable one halfband filter + * handle remainder in CIC + * + * \param rate the requested rate in Sps + * \return the 32-bit cic filter control word + */ + UHD_API boost::uint32_t calc_cic_filter_word(unsigned rate); + + /*! + * Calculate the IQ scale factor word from I and Q components. + * \param i the I component of the scalar + * \param q the Q component of the scalar + * \return the 32-bit scale factor control word + */ + UHD_API boost::uint32_t calc_iq_scale_word( + boost::int16_t i, boost::int16_t q + ); + + /*! + * Calculate the IQ scale factor word from the rate. + * \param rate the requested rate in Sps + * \return the 32-bit scale factor control word + */ + UHD_API boost::uint32_t calc_iq_scale_word(unsigned rate); + + /*! + * Calculate the stream command word from the stream command struct. + * \param stream_cmd the requested stream command with mode, flags, timestamp + * \param num_samps_continuous number of samples to request in continuous mode + * \return the 32-bit stream command word + */ + UHD_API boost::uint32_t calc_stream_cmd_word( + const stream_cmd_t &stream_cmd, size_t num_samps_continuous + ); + +} //namespace dsp_type1 + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_DSP_UTILS_HPP */ diff --git a/host/include/uhd/usrp/misc_utils.hpp b/host/include/uhd/usrp/misc_utils.hpp new file mode 100644 index 000000000..2af9f5b40 --- /dev/null +++ b/host/include/uhd/usrp/misc_utils.hpp @@ -0,0 +1,68 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_USRP_MISC_UTILS_HPP +#define INCLUDED_UHD_USRP_MISC_UTILS_HPP + +#include <uhd/config.hpp> +#include <uhd/wax.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/utils/gain_group.hpp> + +namespace uhd{ namespace usrp{ + + /*! + * Different policies for gain group prioritization. + */ + enum gain_group_policy_t{ + GAIN_GROUP_POLICY_RX = 'R', + GAIN_GROUP_POLICY_TX = 'T' + }; + + /*! + * Create a gain group that represents the subdevice and its codec. + * \param subdev the object with subdevice properties + * \param codec the object with codec properties + * \param gain_group_policy the policy to use + */ + UHD_API gain_group::sptr make_gain_group( + wax::obj subdev, wax::obj codec, + gain_group_policy_t gain_group_policy + ); + + /*! + * Verify the rx subdevice specification. + * If the subdev spec if empty, automatically fill it. + * \param subdev_spec the subdev spec to verify/fill + * \param mboard the motherboard properties object + * \throw exception when the subdev spec is invalid + */ + UHD_API void verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard); + + /*! + * Verify the tx subdevice specification. + * If the subdev spec if empty, automatically fill it. + * \param subdev_spec the subdev spec to verify/fill + * \param mboard the motherboard properties object + * \throw exception when the subdev spec is invalid + */ + UHD_API void verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard); + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_MISC_UTILS_HPP */ + diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index 1b5eacfa9..53c571e4e 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -22,6 +22,9 @@ #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> +#include <boost/algorithm/string.hpp> +#include <vector> +#include <string> /*! \file algorithm.hpp * Useful templated functions and classes that I like to pretend are part of stl. @@ -30,6 +33,24 @@ namespace std{ /*! + * Split a string at the separation characters. + * \param string the string to split + * \param sep the separator characters + * \return a range of strings + */ + inline std::vector<std::string> split_string( + const std::string &string, const std::string &sep = "\t " + ){ + std::vector<std::string> strings; + if (not string.empty()) boost::split( + // do not split an empty string: + // let me tell you about the time when boost::split segfaulted... + strings, string, boost::is_any_of(sep) + ); + return strings; + } + + /*! * A wrapper around std::copy that takes ranges instead of iterators. * * Copy the elements of the source range into the destination range. diff --git a/host/include/uhd/utils/props.hpp b/host/include/uhd/utils/props.hpp index f376d2612..fbca03019 100644 --- a/host/include/uhd/utils/props.hpp +++ b/host/include/uhd/utils/props.hpp @@ -21,7 +21,6 @@ #include <uhd/config.hpp> #include <uhd/wax.hpp> #include <uhd/utils/exception.hpp> -#include <boost/tuple/tuple.hpp> #include <stdexcept> #include <vector> #include <string> @@ -36,8 +35,25 @@ namespace uhd{ * Allows properties to be sub-sectioned by name. */ struct UHD_API named_prop_t{ - wax::obj key; - std::string name; + const wax::obj key; + const std::string name; + + //! Convert the key to the specified type + template<typename T> inline T as(void){ + return key.as<T>(); + } + + /*! + * Utility function to convert generic key into a named prop. + * If the key was already a named prop, the prop will be split. + * Otherwise, the key will be the key, and the name will be used. + * \param key a reference to the prop object + * \param name a reference to the name object + * \return a named property struct with key and name + */ + static named_prop_t extract( + const wax::obj &key, const std::string &name = "" + ); /*! * Create a new named prop from key and name. @@ -48,17 +64,6 @@ namespace uhd{ }; /*! - * 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 = "" - ); - - /*! * Throw when getting a not-implemented or write-only property. * Throw-site information will be included with this error. */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 48cfe742e..81845de21 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -53,6 +53,17 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/utils/CMakeLists.txt) ######################################################################## # Append to the list of sources for lib uhd ######################################################################## +FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/${PKG_DATA_DIR} LOCAL_PKG_DATA_DIR) +STRING(REPLACE "\\" "\\\\" LOCAL_PKG_DATA_DIR ${LOCAL_PKG_DATA_DIR}) +MESSAGE(STATUS "Local package data directory: ${LOCAL_PKG_DATA_DIR}") + +IF(UNIX) + #on unix systems, installers will use this directory for the package data + FILE(TO_NATIVE_PATH /usr/${PKG_DATA_DIR} INSTALLER_PKG_DATA_DIR) + STRING(REPLACE "\\" "\\\\" INSTALLER_PKG_DATA_DIR ${INSTALLER_PKG_DATA_DIR}) + MESSAGE(STATUS "Installer package data directory: ${INSTALLER_PKG_DATA_DIR}") +ENDIF(UNIX) + CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/constants.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp diff --git a/host/lib/constants.hpp.in b/host/lib/constants.hpp.in index aa51e558c..4aedb6d4a 100644 --- a/host/lib/constants.hpp.in +++ b/host/lib/constants.hpp.in @@ -18,12 +18,9 @@ #ifndef INCLUDED_LIBUHD_CONSTANTS_HPP #define INCLUDED_LIBUHD_CONSTANTS_HPP -#include <uhd/config.hpp> -#include <string> - //these should be pre-processor macros to avoid static initialization issues #define UHD_VERSION_STRING "@CPACK_PACKAGE_VERSION@" -#define UHD_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" -#define UHD_PKG_DATA_DIR "@PKG_DATA_DIR@" +#define LOCAL_PKG_DATA_DIR "@LOCAL_PKG_DATA_DIR@" +#define INSTALLER_PKG_DATA_DIR "@INSTALLER_PKG_DATA_DIR@" #endif /* INCLUDED_LIBUHD_CONSTANTS_HPP */ diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 5c0fb1f42..f957cd83f 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -27,7 +27,6 @@ #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> @@ -181,15 +180,10 @@ static std::string trim(const std::string &in){ } 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, boost::is_any_of(arg_delim)); - BOOST_FOREACH(const std::string &pair, pairs){ + BOOST_FOREACH(const std::string &pair, std::split_string(args, arg_delim)){ 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)); + std::vector<std::string> key_val = std::split_string(pair, pair_delim); if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); (*this)[trim(key_val.front())] = trim(key_val.back()); } @@ -238,13 +232,12 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ throw std::runtime_error("expected exactly 5 or 17 characters"); //split the mac addr hex string at the colons - std::vector<std::string> hex_strs; - boost::split(hex_strs, mac_addr_str, boost::is_any_of(":")); - for (size_t i = 0; i < hex_strs.size(); i++){ + size_t i = 0; + BOOST_FOREACH(const std::string &hex_str, std::split_string(mac_addr_str, ":")){ int hex_num; - std::istringstream iss(hex_strs[i]); + std::istringstream iss(hex_str); iss >> std::hex >> hex_num; - bytes[i] = boost::uint8_t(hex_num); + bytes[i++] = boost::uint8_t(hex_num); } } diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index d951ab412..2b408e479 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -22,10 +22,9 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_eeprom.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 9180828d8..f8236d598 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -95,8 +95,7 @@ basic_rx::~basic_rx(void){ } void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -161,8 +160,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ } void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -194,8 +192,7 @@ basic_tx::~basic_tx(void){ } void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -252,8 +249,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ } void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 03e6b6255..06cf91d3b 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -61,7 +61,7 @@ static const uhd::dict<std::string, gain_range_t> dbsrx_gain_ranges = map_list_o **********************************************************************/ class dbsrx : public rx_dboard_base{ public: - dbsrx(ctor_args_t args, boost::uint8_t max2118_addr); + dbsrx(ctor_args_t args); ~dbsrx(void); void rx_get(const wax::obj &key, wax::obj &val); @@ -73,7 +73,9 @@ private: uhd::dict<std::string, float> _gains; max2118_write_regs_t _max2118_write_regs; max2118_read_regs_t _max2118_read_regs; - boost::uint8_t _max2118_addr; //0x67 or 0x65 depending on which side + boost::uint8_t _max2118_addr(void){ + return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x65 : 0x67; + }; void set_lo_freq(double target_freq); void set_gain(float gain, const std::string &name); @@ -102,7 +104,7 @@ private: //send the data this->get_iface()->write_i2c( - _max2118_addr, regs_vector + _max2118_addr(), regs_vector ); } } @@ -120,7 +122,7 @@ private: //read from i2c regs_vector = this->get_iface()->read_i2c( - _max2118_addr, num_bytes + _max2118_addr(), num_bytes ); for(boost::uint8_t i=0; i < num_bytes; i++){ @@ -156,10 +158,8 @@ private: /*********************************************************************** * Register the DBSRX dboard **********************************************************************/ -// FIXME 0x67 is the default i2c address on USRP2 -// need to handle which side for USRP1 with different address static dboard_base::sptr make_dbsrx(dboard_base::ctor_args_t args){ - return dboard_base::sptr(new dbsrx(args, 0x67)); + return dboard_base::sptr(new dbsrx(args)); } //dbid for USRP2 version @@ -177,27 +177,27 @@ UHD_STATIC_BLOCK(reg_dbsrx_on_usrp1_dboard){ /*********************************************************************** * Structors **********************************************************************/ -dbsrx::dbsrx(ctor_args_t args, boost::uint8_t max2118_addr) : rx_dboard_base(args){ +dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){ //warn user about incorrect DBID on USRP1, requires R193 populated - if (this->get_iface()->get_mboard_name() == "usrp1" and this->get_rx_id() == 0x000D) + if (this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x000D) uhd::print_warning( str(boost::format( "DBSRX: incorrect dbid\n" - "%s expects dbid 0x0002 and R193\n" + "Expected dbid 0x0002 and R193\n" "found dbid == %d\n" "Please see the daughterboard app notes" - ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) + ) % this->get_rx_id().to_pp_string()) ); //warn user about incorrect DBID on non-USRP1, requires R194 populated - if (this->get_iface()->get_mboard_name() != "usrp1" and this->get_rx_id() == 0x0002) + if (not this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x0002) uhd::print_warning( str(boost::format( "DBSRX: incorrect dbid\n" - "%s expects dbid 0x000D and R194\n" + "Expected dbid 0x000D and R194\n" "found dbid == %d\n" "Please see the daughterboard app notes" - ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) + ) % this->get_rx_id().to_pp_string()) ); //enable only the clocks we need @@ -207,9 +207,6 @@ dbsrx::dbsrx(ctor_args_t args, boost::uint8_t max2118_addr) : rx_dboard_base(arg this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs - //set the i2c address for the max2118 - _max2118_addr = max2118_addr; - //send initial register settings this->send_reg(0x0, 0x5); @@ -503,8 +500,7 @@ void dbsrx::set_bandwidth(float bandwidth){ * RX Get and Set **********************************************************************/ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -517,13 +513,13 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_gains.keys(), name, "dbsrx gain name"); - val = _gains[name]; + assert_has(_gains.keys(), key.name, "dbsrx gain name"); + val = _gains[key.name]; return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name"); - val = dbsrx_gain_ranges[name]; + assert_has(dbsrx_gain_ranges.keys(), key.name, "dbsrx gain name"); + val = dbsrx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -546,19 +542,6 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ val = dbsrx_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_CONNECTION: val = SUBDEV_CONN_COMPLEX_IQ; return; @@ -586,8 +569,7 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ } void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -597,7 +579,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_gain(val.as<float>(), name); + this->set_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_BANDWIDTH: diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index b6b44199a..c3ab96e59 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -398,8 +398,7 @@ double rfx_xcvr::set_lo_freq( * RX Get and Set **********************************************************************/ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -412,13 +411,13 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_rx_gains.keys(), name, "rfx rx gain name"); - val = _rx_gains[name]; + assert_has(_rx_gains.keys(), key.name, "rfx rx gain name"); + val = _rx_gains[key.name]; return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name"); - val = _rx_gain_ranges[name]; + assert_has(_rx_gain_ranges.keys(), key.name, "rfx rx gain name"); + val = _rx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -458,8 +457,7 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ } void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -469,7 +467,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_rx_gain(val.as<float>(), name); + this->set_rx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: @@ -484,8 +482,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; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -499,7 +496,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ case SUBDEV_PROP_GAIN: case SUBDEV_PROP_GAIN_RANGE: - assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name"); + assert_has(rfx_tx_gain_ranges.keys(), key.name, "rfx tx gain name"); //no controllable tx gains, will not get here return; @@ -540,8 +537,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ } void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -551,7 +547,7 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_tx_gain(val.as<float>(), name); + this->set_tx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index 9dd9b550b..f6f4f4a61 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -78,8 +78,7 @@ unknown_rx::~unknown_rx(void){ } void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -136,8 +135,7 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){ } void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -169,8 +167,7 @@ unknown_tx::~unknown_tx(void){ } void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -227,8 +224,7 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){ } void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 3038ce30b..ccd897674 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -467,8 +467,7 @@ double wbx_xcvr::set_lo_freq( * RX Get and Set **********************************************************************/ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -481,13 +480,13 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_rx_gains.keys(), name, "wbx rx gain name"); - val = _rx_gains[name]; + assert_has(_rx_gains.keys(), key.name, "wbx rx gain name"); + val = _rx_gains[key.name]; return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(wbx_rx_gain_ranges.keys(), name, "wbx rx gain name"); - val = wbx_rx_gain_ranges[name]; + assert_has(wbx_rx_gain_ranges.keys(), key.name, "wbx rx gain name"); + val = wbx_rx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -527,8 +526,7 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ } void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -538,7 +536,7 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_rx_gain(val.as<float>(), name); + this->set_rx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: @@ -553,8 +551,7 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ * TX Get and Set **********************************************************************/ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -567,13 +564,13 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_tx_gains.keys(), name, "wbx tx gain name"); - val = _tx_gains[name]; + assert_has(_tx_gains.keys(), key.name, "wbx tx gain name"); + val = _tx_gains[key.name]; return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(wbx_tx_gain_ranges.keys(), name, "wbx tx gain name"); - val = wbx_tx_gain_ranges[name]; + assert_has(wbx_tx_gain_ranges.keys(), key.name, "wbx tx gain name"); + val = wbx_tx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -613,8 +610,7 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ } void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -624,7 +620,7 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_tx_gain(val.as<float>(), name); + this->set_tx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 2c94bcd2d..798ff74a3 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -438,8 +438,7 @@ void xcvr2450::set_rx_gain(float gain, const std::string &name){ * 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_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -452,13 +451,13 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_rx_gains.keys(), name, "xcvr rx gain name"); - val = _rx_gains[name]; + assert_has(_rx_gains.keys(), key.name, "xcvr rx gain name"); + val = _rx_gains[key.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]; + assert_has(xcvr_rx_gain_ranges.keys(), key.name, "xcvr rx gain name"); + val = xcvr_rx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -502,8 +501,7 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){ } 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_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -513,7 +511,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_rx_gain(val.as<float>(), name); + this->set_rx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: @@ -528,8 +526,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){ * 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_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -542,13 +539,13 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - assert_has(_tx_gains.keys(), name, "xcvr tx gain name"); - val = _tx_gains[name]; + assert_has(_tx_gains.keys(), key.name, "xcvr tx gain name"); + val = _tx_gains[key.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]; + assert_has(xcvr_tx_gain_ranges.keys(), key.name, "xcvr tx gain name"); + val = xcvr_tx_gain_ranges[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: @@ -588,8 +585,7 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){ } 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_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<subdev_prop_t>()){ @@ -599,7 +595,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){ return; case SUBDEV_PROP_GAIN: - this->set_tx_gain(val.as<float>(), name); + this->set_tx_gain(val.as<float>(), key.name); return; case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dsp_utils.cpp b/host/lib/usrp/dsp_utils.cpp new file mode 100644 index 000000000..fe1313af1 --- /dev/null +++ b/host/lib/usrp/dsp_utils.cpp @@ -0,0 +1,124 @@ +// +// 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/dsp_utils.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/math/special_functions/round.hpp> +#include <cmath> + +using namespace uhd; +using namespace uhd::usrp; + +template <class T> T ceil_log2(T num){ + return std::ceil(std::log(num)/std::log(T(2))); +} + +boost::uint32_t dsp_type1::calc_rx_mux_word(subdev_conn_t subdev_conn){ + switch(subdev_conn){ + case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 2) | (0x0 << 0); //DDC0Q=ADC1, DDC0I=ADC0 + case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 2) | (0x1 << 0); //DDC0Q=ADC0, DDC0I=ADC1 + case SUBDEV_CONN_REAL_I: return (0x3 << 2) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0 + case SUBDEV_CONN_REAL_Q: return (0x1 << 2) | (0x3 << 0); //DDC0Q=ADC1, DDC0I=ZERO + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +boost::uint32_t dsp_type1::calc_tx_mux_word(subdev_conn_t subdev_conn){ + switch(subdev_conn){ + case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC1=DUC0Q, DAC0=DUC0I + case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC1=DUC0I, DAC0=DUC0Q + case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC1=ZERO, DAC0=DUC0I + case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC1=DUC0I, DAC0=ZERO + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +boost::uint32_t dsp_type1::calc_cordic_word_and_update( + double &freq, + double codec_rate +){ + UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0); + static const double scale_factor = std::pow(2.0, 32); + + //calculate the freq register word (signed) + boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / codec_rate) * scale_factor)); + + //update the actual frequency + freq = (double(freq_word) / scale_factor) * codec_rate; + + return boost::uint32_t(freq_word); +} + +boost::uint32_t dsp_type1::calc_cic_filter_word(unsigned rate){ + int hb0 = 0, hb1 = 0; + if (not (rate & 0x1)){ + hb0 = 1; + rate /= 2; + } + if (not (rate & 0x1)){ + hb1 = 1; + rate /= 2; + } + return (hb1 << 9) | (hb0 << 8) | (rate & 0xff); +} + +boost::uint32_t dsp_type1::calc_iq_scale_word( + boost::int16_t i, boost::int16_t q +){ + return (boost::uint32_t(i) << 16) | (boost::uint32_t(q) << 0); +} + +boost::uint32_t dsp_type1::calc_iq_scale_word(unsigned rate){ + // Calculate CIC interpolation (i.e., without halfband interpolators) + unsigned tmp_rate = calc_cic_filter_word(rate) & 0xff; + + // Calculate closest multiplier constant to reverse gain absent scale multipliers + double rate_cubed = std::pow(double(tmp_rate), 3); + boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed)); + return calc_iq_scale_word(scale, scale); +} + +boost::uint32_t dsp_type1::calc_stream_cmd_word( + const stream_cmd_t &stream_cmd, size_t num_samps_continuous +){ + UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff); + + //setup the mode to instruction flags + typedef boost::tuple<bool, bool, bool> inst_t; + static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of + //reload, chain, samps + (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) + (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) + ; + + //setup the instruction flag values + bool inst_reload, inst_chain, inst_samps; + boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; + + //calculate the word from flags and length + boost::uint32_t word = 0; + word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; + word |= boost::uint32_t((inst_chain)? 1 : 0) << 30; + word |= boost::uint32_t((inst_reload)? 1 : 0) << 29; + word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? num_samps_continuous : 1); + return word; +} diff --git a/host/lib/usrp/dsp_utils.hpp b/host/lib/usrp/dsp_utils.hpp deleted file mode 100644 index ebed12c41..000000000 --- a/host/lib/usrp/dsp_utils.hpp +++ /dev/null @@ -1,187 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_LIBUHD_USRP_DSP_UTILS_HPP -#define INCLUDED_LIBUHD_USRP_DSP_UTILS_HPP - -#include <uhd/config.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/assert.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <boost/cstdint.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/tuple/tuple.hpp> -#include <boost/math/special_functions/round.hpp> - -namespace uhd{ namespace usrp{ - -namespace dsp_type1{ - - template <class T> T ceil_log2(T num){ - return std::ceil(std::log(num)/std::log(T(2))); - } - - /*! - * Calculate the rx mux word from properties. - * \param subdev_conn the subdev connection type - * \param the 32-bit rx mux control word - */ - static inline boost::uint32_t calc_rx_mux_word( - subdev_conn_t subdev_conn - ){ - switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 2) | (0x0 << 0); //DDC0Q=ADC1, DDC0I=ADC0 - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 2) | (0x1 << 0); //DDC0Q=ADC0, DDC0I=ADC1 - case SUBDEV_CONN_REAL_I: return (0x3 << 2) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0 - case SUBDEV_CONN_REAL_Q: return (0x1 << 2) | (0x3 << 0); //DDC0Q=ADC1, DDC0I=ZERO - default: UHD_THROW_INVALID_CODE_PATH(); - } - } - - /*! - * Calculate the tx mux word from properties. - * \param subdev_conn the subdev connection type - * \param the 32-bit tx mux control word - */ - static inline boost::uint32_t calc_tx_mux_word( - subdev_conn_t subdev_conn - ){ - switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC1=DUC0Q, DAC0=DUC0I - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC1=DUC0I, DAC0=DUC0Q - case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC1=ZERO, DAC0=DUC0I - case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC1=DUC0I, DAC0=ZERO - default: UHD_THROW_INVALID_CODE_PATH(); - } - } - - /*! - * Calculate the cordic word from the frequency and clock rate. - * The frequency will be set to the actual (possible) frequency. - * - * \param freq the requested frequency in Hz - * \param codec_rate the dsp codec rate in Hz - * \param the 32-bit cordic control word - */ - static inline boost::uint32_t calc_cordic_word_and_update( - double &freq, - double codec_rate - ){ - UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0); - static const double scale_factor = std::pow(2.0, 32); - - //calculate the freq register word (signed) - boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / codec_rate) * scale_factor)); - - //update the actual frequency - freq = (double(freq_word) / scale_factor) * codec_rate; - - return boost::uint32_t(freq_word); - } - - /*! - * Calculate the CIC filter word from the rate. - * Check if requested decim/interp rate is: - * multiple of 4, enable two halfband filters - * multiple of 2, enable one halfband filter - * handle remainder in CIC - * - * \param rate the requested rate in Sps - * \return the 32-bit cic filter control word - */ - template <typename dsp_rate_type> - static inline boost::uint32_t calc_cic_filter_word(dsp_rate_type rate){ - int hb0 = 0, hb1 = 0; - if (not (rate & 0x1)){ - hb0 = 1; - rate /= 2; - } - if (not (rate & 0x1)){ - hb1 = 1; - rate /= 2; - } - return (hb1 << 9) | (hb0 << 8) | (rate & 0xff); - } - - /*! - * Calculate the IQ scale factor word from I and Q components. - * \param i the I component of the scalar - * \param q the Q component of the scalar - * \return the 32-bit scale factor control word - */ - static inline boost::uint32_t calc_iq_scale_word( - boost::int16_t i, boost::int16_t q - ){ - return (boost::uint32_t(i) << 16) | (boost::uint32_t(q) << 0); - } - - /*! - * Calculate the IQ scale factor word from the rate. - * \param rate the requested rate in Sps - * \return the 32-bit scale factor control word - */ - template <typename dsp_rate_type> - static inline boost::uint32_t calc_iq_scale_word(dsp_rate_type rate){ - // Calculate CIC interpolation (i.e., without halfband interpolators) - dsp_rate_type tmp_rate = calc_cic_filter_word(rate) & 0xff; - - // Calculate closest multiplier constant to reverse gain absent scale multipliers - double rate_cubed = std::pow(double(tmp_rate), 3); - boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed)); - return calc_iq_scale_word(scale, scale); - } - - /*! - * Calculate the stream command word from the stream command struct. - * \param stream_cmd the requested stream command with mode, flags, timestamp - * \param num_samps_continuous number of samples to request in continuous mode - * \return the 32-bit stream command word - */ - static inline boost::uint32_t calc_stream_cmd_word( - const stream_cmd_t &stream_cmd, size_t num_samps_continuous - ){ - UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff); - - //setup the mode to instruction flags - typedef boost::tuple<bool, bool, bool> inst_t; - static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of - //reload, chain, samps - (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) - (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) - (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) - (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) - ; - - //setup the instruction flag values - bool inst_reload, inst_chain, inst_samps; - boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; - - //calculate the word from flags and length - boost::uint32_t word = 0; - word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; - word |= boost::uint32_t((inst_chain)? 1 : 0) << 30; - word |= boost::uint32_t((inst_reload)? 1 : 0) << 29; - word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? num_samps_continuous : 1); - return word; - } - -} //namespace dsp_type1 - -}} //namespace - -#endif /* INCLUDED_LIBUHD_USRP_DSP_UTILS_HPP */ diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index 0aa03a6cc..46094ba32 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -15,9 +15,13 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "misc_utils.hpp" +#include <uhd/usrp/misc_utils.hpp> +#include <uhd/utils/assert.hpp> #include <uhd/utils/gain_group.hpp> +#include <uhd/usrp/dboard_id.hpp> #include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/mboard_props.hpp> +#include <uhd/usrp/dboard_props.hpp> #include <uhd/usrp/codec_props.hpp> #include <boost/bind.hpp> #include <boost/foreach.hpp> @@ -25,9 +29,6 @@ using namespace uhd; using namespace uhd::usrp; -static const size_t subdev_gain_priority = 1; //higher, closer to the antenna -static const size_t codec_gain_priority = 0; - /*********************************************************************** * codec gain group helper functions: * do this so we dont have to bind a templated function @@ -76,7 +77,15 @@ static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain /*********************************************************************** * gain group factory function for usrp **********************************************************************/ -gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){ +gain_group::sptr usrp::make_gain_group( + wax::obj subdev, wax::obj codec, + gain_group_policy_t gain_group_policy +){ + const size_t subdev_gain_priority = 1; + const size_t codec_gain_priority = (gain_group_policy == GAIN_GROUP_POLICY_RX)? + (subdev_gain_priority - 1): //RX policy, codec gains fill last (lower priority) + (subdev_gain_priority + 1); //TX policy, codec gains fill first (higher priority) + gain_group::sptr gg = gain_group::make(); gain_fcns_t fcns; //add all the subdev gains first (antenna to dsp order) @@ -112,3 +121,69 @@ gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){ } return gg; } + +/*********************************************************************** + * verify subdev specs + **********************************************************************/ +static void verify_xx_subdev_spec( + mboard_prop_t dboard_names_prop, + mboard_prop_t dboard_prop, + subdev_spec_t &subdev_spec, + wax::obj mboard, + std::string xx_type +){ + prop_names_t dboard_names = mboard[dboard_names_prop].as<prop_names_t>(); + UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard + + //the subdevice specification is empty: handle automatic + if (subdev_spec.empty()){ + BOOST_FOREACH(const std::string &db_name, dboard_names){ + wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; + + //if the dboard slot is populated, take the first subdevice + if (dboard[DBOARD_PROP_DBOARD_ID].as<dboard_id_t>() != dboard_id_t::none()){ + std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front(); + subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); + break; + } + } + + //didnt find any populated dboards: add the first subdevice + if (subdev_spec.empty()){ + std::string db_name = dboard_names.front(); + wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; + std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front(); + subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); + } + } + + //sanity check that the dboard/subdevice names exist for this mboard + BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ + //empty db name means select dboard automatically + if (pair.db_name.empty()){ + if (dboard_names.size() != 1) throw std::runtime_error( + "A daughterboard name must be provided for multi-slot boards: " + subdev_spec.to_string() + ); + pair.db_name == dboard_names.front(); + } + uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); + wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; + uhd::assert_has(dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>(), pair.sd_name, xx_type + " subdev name"); + } +} + +void usrp::verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){ + return verify_xx_subdev_spec( + MBOARD_PROP_RX_DBOARD_NAMES, + MBOARD_PROP_RX_DBOARD, + subdev_spec, mboard, "rx" + ); +} + +void usrp::verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){ + return verify_xx_subdev_spec( + MBOARD_PROP_TX_DBOARD_NAMES, + MBOARD_PROP_TX_DBOARD, + subdev_spec, mboard, "tx" + ); +} diff --git a/host/lib/usrp/misc_utils.hpp b/host/lib/usrp/misc_utils.hpp deleted file mode 100644 index 7fe3c899d..000000000 --- a/host/lib/usrp/misc_utils.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP -#define INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP - -#include <uhd/config.hpp> -#include <uhd/wax.hpp> -#include <uhd/utils/gain_group.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Create a gain group that represents the subdevice and its codec. - */ - gain_group::sptr make_gain_group(wax::obj subdev, wax::obj codec); - -}} //namespace - -#endif /* INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP */ - diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp index 0f00e2f74..7a3e72867 100644 --- a/host/lib/usrp/subdev_spec.cpp +++ b/host/lib/usrp/subdev_spec.cpp @@ -16,7 +16,7 @@ // #include <uhd/usrp/subdev_spec.hpp> -#include <boost/algorithm/string.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <stdexcept> @@ -35,12 +35,9 @@ subdev_spec_pair_t::subdev_spec_pair_t( } subdev_spec_t::subdev_spec_t(const std::string &markup){ - std::vector<std::string> pairs; - boost::split(pairs, markup, boost::is_any_of("\t ")); - BOOST_FOREACH(const std::string &pair, pairs){ + BOOST_FOREACH(const std::string &pair, std::split_string(markup)){ if (pair == "") continue; - std::vector<std::string> db_sd; - boost::split(db_sd, pair, boost::is_any_of(":")); + std::vector<std::string> db_sd = std::split_string(pair, ":"); switch(db_sd.size()){ case 1: this->push_back(subdev_spec_pair_t("", db_sd.front())); break; case 2: this->push_back(subdev_spec_pair_t(db_sd.front(), db_sd.back())); break; @@ -56,13 +53,9 @@ std::string subdev_spec_t::to_pp_string(void) const{ size_t count = 0; ss << "Subdevice Specification:" << std::endl; BOOST_FOREACH(const subdev_spec_pair_t &pair, *this){ - std::string db_name = pair.db_name; - if (db_name == "") db_name = "0"; - std::string sd_name = pair.sd_name; - if (sd_name == "") sd_name = "0"; ss << boost::format( " Channel %d: Daughterboard %s, Subdevice %s" - ) % (count++) % db_name % sd_name << std::endl; + ) % (count++) % pair.db_name % pair.sd_name << std::endl; } return ss.str(); } diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp index 969b5b4b9..f7f9ce2d5 100644 --- a/host/lib/usrp/usrp2/codec_impl.cpp +++ b/host/lib/usrp/usrp2/codec_impl.cpp @@ -53,9 +53,7 @@ void usrp2_mboard_impl::codec_init(void){ /*********************************************************************** * RX Codec Properties **********************************************************************/ -void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); +void usrp2_mboard_impl::rx_codec_get(const wax::obj &key, wax::obj &val){ //handle the get request conditioned on the key switch(key.as<codec_prop_t>()){ @@ -136,9 +134,7 @@ void usrp2_mboard_impl::rx_codec_set_gain(float gain, const std::string &name){ /*********************************************************************** * TX Codec Properties **********************************************************************/ -void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); +void usrp2_mboard_impl::tx_codec_get(const wax::obj &key, wax::obj &val){ //handle the get request conditioned on the key switch(key.as<codec_prop_t>()){ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index be45c2c9e..cff13292b 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -37,7 +37,12 @@ public: usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl); ~usrp2_dboard_iface(void); - std::string get_mboard_name(void){return "usrp2";} + special_props_t get_special_props(void){ + special_props_t props; + props.soft_clock_divider = false; + props.mangle_i2c_addrs = false; + return props; + } void write_aux_dac(unit_t, aux_dac_t, float); float read_aux_adc(unit_t, aux_adc_t); diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 075f22388..a462b93c2 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -17,8 +17,8 @@ #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" -#include "../dsp_utils.hpp" -#include "../misc_utils.hpp" +#include <uhd/usrp/misc_utils.hpp> +#include <uhd/usrp/dsp_utils.hpp> #include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_props.hpp> #include <uhd/utils/assert.hpp> @@ -59,8 +59,7 @@ void usrp2_mboard_impl::dboard_init(void){ * RX DBoard Properties **********************************************************************/ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<dboard_prop_t>()){ @@ -69,7 +68,7 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(name); + val = _dboard_manager->get_rx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -90,7 +89,9 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ case DBOARD_PROP_GAIN_GROUP: val = make_gain_group( - _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link() + _dboard_manager->get_rx_subdev(key.name), + _rx_codec_proxy->get_link(), + GAIN_GROUP_POLICY_RX ); return; @@ -114,8 +115,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ * TX DBoard Properties **********************************************************************/ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<dboard_prop_t>()){ @@ -124,7 +124,7 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(name); + val = _dboard_manager->get_tx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -145,7 +145,9 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ case DBOARD_PROP_GAIN_GROUP: val = make_gain_group( - _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link() + _dboard_manager->get_tx_subdev(key.name), + _tx_codec_proxy->get_link(), + GAIN_GROUP_POLICY_TX ); return; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 936b1f7a2..97bda51fc 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -17,9 +17,10 @@ #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" -#include "../dsp_utils.hpp" +#include <uhd/usrp/dsp_utils.hpp> #include <uhd/usrp/dsp_props.hpp> #include <boost/bind.hpp> +#include <cmath> using namespace uhd; using namespace uhd::usrp; @@ -30,10 +31,10 @@ static const size_t default_interp = 16; /*********************************************************************** * DDC Helper Methods **********************************************************************/ -template <class rate_t> static rate_t -pick_closest_rate(double exact_rate, const std::vector<rate_t> &rates){ - rate_t closest_match = rates.at(0); - BOOST_FOREACH(rate_t possible_rate, rates){ +template <typename rate_type> +static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){ + unsigned closest_match = rates.front(); + BOOST_FOREACH(rate_type possible_rate, rates){ if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match)) closest_match = possible_rate; } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index fc1e6f2a7..4d3b62d6b 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -34,7 +34,7 @@ extern "C" { //fpga and firmware compatibility numbers #define USRP2_FPGA_COMPAT_NUM 1 -#define USRP2_FW_COMPAT_NUM 5 +#define USRP2_FW_COMPAT_NUM 6 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 6c4234641..fc1cc3a9a 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -17,13 +17,15 @@ #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" -#include "../dsp_utils.hpp" +#include <uhd/usrp/misc_utils.hpp> +#include <uhd/usrp/dsp_utils.hpp> #include <uhd/usrp/mboard_props.hpp> #include <uhd/utils/assert.hpp> #include <uhd/utils/algorithm.hpp> #include <uhd/types/mac_addr.hpp> #include <uhd/types/dict.hpp> #include <boost/bind.hpp> +#include <boost/assign/list_of.hpp> #include <boost/asio/ip/address_v4.hpp> #include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> @@ -194,12 +196,13 @@ void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ /*********************************************************************** * MBoard Get Properties **********************************************************************/ +static const std::string dboard_name = "0"; + void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the other props - if (key.type() == typeid(std::string)){ + if (key_.type() == typeid(std::string)){ if (key.as<std::string>() == "mac-addr"){ byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6); val = mac_addr_t::from_bytes(bytes).to_string(); @@ -230,25 +233,25 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == dboard_name); val = _rx_dboard_proxy->get_link(); return; case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, ""); + val = prop_names_t(1, dboard_name); return; case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == dboard_name); val = _tx_dboard_proxy->get_link(); return; case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, ""); + val = prop_names_t(1, dboard_name); return; case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _rx_dsp_proxy->get_link(); return; @@ -257,7 +260,7 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _tx_dsp_proxy->get_link(); return; @@ -333,14 +336,9 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as<subdev_spec_t>(); - //handle automatic - if (_rx_subdev_spec.empty()) _rx_subdev_spec.push_back( - subdev_spec_pair_t("", _dboard_manager->get_rx_subdev_names().front()) - ); + verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); //sanity check UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1); - uhd::assert_has((*this)[MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>(), _rx_subdev_spec.front().db_name, "rx dboard names"); - uhd::assert_has(_dboard_manager->get_rx_subdev_names(), _rx_subdev_spec.front().sd_name, "rx subdev names"); //set the mux _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word( _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() @@ -349,14 +347,9 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_TX_SUBDEV_SPEC: _tx_subdev_spec = val.as<subdev_spec_t>(); - //handle automatic - if (_tx_subdev_spec.empty()) _tx_subdev_spec.push_back( - subdev_spec_pair_t("", _dboard_manager->get_tx_subdev_names().front()) - ); + verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); //sanity check UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1); - uhd::assert_has((*this)[MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>(), _tx_subdev_spec.front().db_name, "tx dboard names"); - uhd::assert_has(_dboard_manager->get_tx_subdev_names(), _tx_subdev_spec.front().sd_name, "tx subdev names"); //set the mux _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word( _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 21f411afe..568c87a22 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -21,7 +21,7 @@ #include <uhd/usrp/device_props.hpp> #include <uhd/utils/assert.hpp> #include <uhd/utils/static.hpp> -#include <boost/algorithm/string.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/assign/list_of.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> @@ -41,12 +41,6 @@ static const size_t DISCOVERY_TIMEOUT_MS = 100; /*********************************************************************** * Helper Functions **********************************************************************/ -std::vector<std::string> split_addrs(const std::string &addrs_str){ - std::vector<std::string> addrs; - boost::split(addrs, addrs_str, boost::is_any_of("\t ")); - return addrs; -} - template <class T> std::string num2str(T num){ return boost::lexical_cast<std::string>(num); } @@ -80,7 +74,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){ } //if there are multiple addresses, just return good, dont test - std::vector<std::string> addrs = split_addrs(hint["addr"]); + std::vector<std::string> addrs = std::split_string(hint["addr"]); if (addrs.size() > 1){ device_addr_t new_addr; new_addr["type"] = "usrp2"; @@ -155,7 +149,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){ std::vector<udp_simple::sptr> ctrl_transports; std::vector<udp_zero_copy::sptr> data_transports; - BOOST_FOREACH(const std::string &addr, split_addrs(device_addr["addr"])){ + BOOST_FOREACH(const std::string &addr, std::split_string(device_addr["addr"])){ ctrl_transports.push_back(udp_simple::make_connected( addr, num2str(USRP2_UDP_CTRL_PORT) )); @@ -207,8 +201,7 @@ usrp2_impl::~usrp2_impl(void){ * Device Properties **********************************************************************/ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as<device_prop_t>()){ @@ -218,7 +211,7 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MBOARD: - val = _mboard_dict[name]->get_link(); + val = _mboard_dict[key.name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index 4029bd989..6ad12d3cc 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -17,7 +17,7 @@ #include "constants.hpp" #include <uhd/config.hpp> -#include <boost/algorithm/string.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/program_options.hpp> #include <boost/filesystem.hpp> #include <boost/foreach.hpp> @@ -58,15 +58,9 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){ po::store(po::parse_environment(desc, boost::bind(&name_mapper, var_name, _1)), vm); po::notify(vm); - //split the path at the path separators - std::vector<std::string> path_strings; - if (not var_value.empty()) boost::split(//dont split empty strings - path_strings, var_value, boost::is_any_of(env_path_sep) - ); - //convert to filesystem path, filter blank paths std::vector<fs::path> paths; - BOOST_FOREACH(std::string &path_string, path_strings){ + BOOST_FOREACH(const std::string &path_string, std::split_string(var_value, env_path_sep)){ if (path_string.empty()) continue; paths.push_back(fs::system_complete(path_string)); } @@ -78,13 +72,17 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){ **********************************************************************/ std::vector<fs::path> get_image_paths(void){ std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH"); - paths.push_back(fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR / "images"); + paths.push_back(fs::path(LOCAL_PKG_DATA_DIR) / "images"); + if (not std::string(INSTALLER_PKG_DATA_DIR).empty()) + paths.push_back(fs::path(INSTALLER_PKG_DATA_DIR) / "images"); return paths; } std::vector<fs::path> get_module_paths(void){ std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH"); - paths.push_back(fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR / "modules"); + paths.push_back(fs::path(LOCAL_PKG_DATA_DIR) / "modules"); + if (not std::string(INSTALLER_PKG_DATA_DIR).empty()) + paths.push_back(fs::path(INSTALLER_PKG_DATA_DIR) / "modules"); return paths; } diff --git a/host/lib/utils/props.cpp b/host/lib/utils/props.cpp index fac5fe24f..fc9f8e63f 100644 --- a/host/lib/utils/props.cpp +++ b/host/lib/utils/props.cpp @@ -29,15 +29,12 @@ named_prop_t::named_prop_t( /* NOP */ } -typedef boost::tuple<wax::obj, std::string> named_prop_tuple; - -named_prop_tuple uhd::extract_named_prop( +named_prop_t named_prop_t::extract( 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 key.as<named_prop_t>(); } - return named_prop_tuple(key, name); + return named_prop_t(key, name); } diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp index ae4d4c7aa..8a7d35a23 100644 --- a/host/lib/utils/warning.cpp +++ b/host/lib/utils/warning.cpp @@ -16,7 +16,7 @@ // #include <uhd/utils/warning.hpp> -#include <boost/algorithm/string.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/foreach.hpp> #include <iostream> #include <vector> @@ -24,13 +24,9 @@ using namespace uhd; void uhd::print_warning(const std::string &msg){ - //extract the message lines - std::vector<std::string> lines; - boost::split(lines, msg, boost::is_any_of("\n")); - //print the warning message std::cerr << std::endl << "Warning:" << std::endl; - BOOST_FOREACH(const std::string &line, lines){ + BOOST_FOREACH(const std::string &line, std::split_string(msg, "\n")){ std::cerr << " " << line << std::endl; } } diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 097317516..8947034d7 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -18,6 +18,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/device.hpp> #include <uhd/types/ranges.hpp> +#include <uhd/utils/algorithm.hpp> #include <uhd/usrp/device_props.hpp> #include <uhd/usrp/mboard_props.hpp> #include <uhd/usrp/dboard_props.hpp> @@ -26,7 +27,6 @@ #include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_id.hpp> #include <boost/program_options.hpp> -#include <boost/algorithm/string.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <iostream> @@ -43,7 +43,7 @@ static std::string make_border(const std::string &text){ std::stringstream ss; ss << boost::format(" _____________________________________________________") << std::endl; ss << boost::format(" /") << std::endl; - std::vector<std::string> lines; boost::split(lines, text, boost::is_any_of("\n")); + std::vector<std::string> lines = std::split_string(text, "\n"); while (lines.back() == "") lines.pop_back(); //strip trailing newlines if (lines.size()) lines[0] = " " + lines[0]; //indent the title line BOOST_FOREACH(const std::string &line, lines){ |